/*
 * LiteGui.java
 *
 * Created on August 23, 2007, 3:52 PM
 */
package com.lct.eq2.gui;

import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JToggleButton;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.util.Rotation;
import com.lct.eq2.data.Attack;
import com.lct.eq2.data.AttackHashMap;
import com.lct.eq2.data.AverageNode;
import com.lct.eq2.data.Combatant;
import com.lct.eq2.data.CombatantNode;
import com.lct.eq2.data.Duration;
import com.lct.eq2.data.Encounter;
import com.lct.eq2.data.HealSort;
import com.lct.eq2.data.Line;
import com.lct.eq2.data.ParseContainer;
import com.lct.eq2.data.RespawnTimer;
import com.lct.eq2.data.TreeRefresh;
import com.lct.eq2.data.ZoneNode;
import com.lct.eq2.socket.CommSocketThread;
import com.lct.eq2.tail.Tail;
import com.lct.eq2.test.test;
import com.lct.eq2.util.FileDownload;
import java.net.ConnectException;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.TreeSelectionModel;

/**
 *
 * @author  waitek
 */
public class LiteGui extends javax.swing.JFrame {

    private ArrayList encounterHistory = null;
    private boolean propsUpdated = false;
    private boolean restart = false;
    boolean sameComputer = true;
    boolean isNetwork = false;
    private ButtonGroup group = null;
    public CommSocketThread commThread;
    private DefaultMutableTreeNode zonewide = null;
    private DefaultMutableTreeNode root = null;
    private DefaultMutableTreeNode root2 = null;
    private DefaultMutableTreeNode root3 = null;
    private DefaultTableModel model = null;
    public Encounter zonewideEncounter = null;
    private HashMap currentAttacks;
    private HashMap storedEncounterHistory;
    private HashMap zonewideDPS;
    private JFreeChart chart = null;
    private ParsePreviewWindow parseWindow;
    private Properties props = null;
    private String combatLogFileLocation;
    private String systemLogFileLocation;
    private static String fileName;
    private String propFile = "lct.properties";
    private String currentLocation = null;
    private String archiveFilePath = null;
    private String machineName;
    public String characterID;
    private static String version = "1.2.8";
    private Tail combatTail = null;
    private TimerWindow timer = null;
    
    /** Creates new form LiteGui */
    public LiteGui() {
        System.setProperty("java.net.useSystemProxies", "true");
        this.setIconImage(Toolkit.getDefaultToolkit().getImage("eq2.png"));
        this.props = new Properties();
        this.currentAttacks = new HashMap();
        this.zonewideDPS = new HashMap();
        this.storedEncounterHistory = new HashMap();
        this.currentLocation = "Unknown";
        this.encounterHistory = new ArrayList();

        File timerFile = new File("timers.xml");
        if (!timerFile.exists()) {
            FileDownload download = new FileDownload();
            download.download("http://lct-eq2.googlecode.com/files/timers.xml", "timers.xml");
        }

        initComponents();
        boolean firstTime = !this.loadProperties();
        
        if (this.props.containsKey("systemLogPath") && !this.props.getProperty("systemLogPath").equalsIgnoreCase("<setup>")) {
            this.props.setProperty("systemLogPath", this.props.getProperty("systemLogPath").replaceAll("system.log", "chat.log"));
        }

        jTabbedPane1.setTitleAt(0, "Current Zone");
        jTabbedPane1.setTitleAt(1, "Groups");
        jTabbedPane1.setTitleAt(2, "Encounter History");
        
        if (props.containsKey("currentZone")) {
            this.currentLocation = props.getProperty("currentZone");
        }
        
        if (!props.containsKey("sendData")) {
            this.props.setProperty("sendData", "false");
            this.saveProperties();
        }
        
        if (!props.containsKey("parsePrevious")) {
            this.props.setProperty("parsePrevious", "false");
            this.saveProperties();
        }
        
        if (!props.containsKey("zoneClear")) {
            this.props.setProperty("zoneClear", "true");
            this.saveProperties();
        }

        if (!props.containsKey("parsePetDamage")) {
            this.props.setProperty("parsePetDamage", "true");
            this.saveProperties();
        }
        
        this.setCurrentLocation(currentLocation);

        this.sameComputer = Boolean.parseBoolean(props.getProperty("eq2OnSamePC"));
        this.isNetwork = Boolean.parseBoolean(props.getProperty("network"));
        if (props.containsKey("combatLogPath")) {
            if (!props.getProperty("combatLogPath").equalsIgnoreCase("<setup>")) {
                combatTail = new Tail(this, Tail.COMBAT_LOG);
                combatTail.start();
            } else {
                //this.props.setProperty("autoVersionCheck", "true");
            }
        } else {
            if (props.containsKey("logPath")) {
                this.props.put("combatLogPath", props.getProperty("logPath"));
            }
        }
        
        MenuAction loadLog = new MenuAction("Select Character", this);
        MenuAction options = new MenuAction("Options", this);
        MenuAction spellTimerWindow = new MenuAction("Spell Timer Window", this);
        MenuAction exit = new MenuAction("Validate Character", this);

        JMenuItem item;
        item = jMenu.add(loadLog);
        item = jMenu.add(options);
//        item = jMenu.add(exit);
        item = jMenu.add(spellTimerWindow);

        jMenuItem1.setText("Track Respawn");
        jMenuItem2.setText("Copy Damage Parse");
        jMenuItem4.setText("Copy Heal Parse");
        jMenuItem3.setText("Load Zone History");
        jMenuItem20.setText("Generate Avoidance Report");

        jPopupMenu2.add(jMenuItem1);
        jPopupMenu2.add(jMenuItem2);
        jPopupMenu2.add(jMenuItem20);

        jPopupMenu1.add(jMenuItem1);
        jPopupMenu3.add(jMenuItem3);

        this.jMenuBar.add(jMenu);
        this.jMenuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

        String currentFile = this.props.getProperty("currentFile");
        if (currentFile != null) {
            switch (Integer.parseInt(currentFile)) {
                case 0:
                    try {
                        try {
                            copy(new File("LCT.jar"), new File("LCT1.jar"));
                        } catch (FileNotFoundException ex) {
                            //nothing
                        }
                        //this.props.setProperty("currentFile", "0");
                        //saveProperties();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    break;
                case 1:
                    try {
                        copy(new File("LCT1.jar"), new File("LCT.jar"));
                        this.props.setProperty("currentFile", "0");
                        VersionChanges changes = new VersionChanges(this.getVersionChanges(), this.getVersion());
                        changes.setBounds(this.getX() + (this.getWidth() / 2) - (changes.getWidth() / 2),
                                this.getY() + (this.getHeight() / 2) - (changes.getHeight() / 2),
                                changes.getWidth(), changes.getHeight());
                        changes.setVisible(true);
                        changes.setAlwaysOnTop(true);
                        changes.setDefaultCloseOperation(changes.DISPOSE_ON_CLOSE);
                        saveProperties();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    break;
                default:
                    break;
            }
        } else {
            currentFile = "0";
            this.props.setProperty("currentFile", currentFile);
            saveProperties();
        }

        String autoVersionCheck = this.props.getProperty("autoVersionCheck");
        if (autoVersionCheck != null) {
            if (autoVersionCheck.equalsIgnoreCase("true")) {
                VersionChecker checker = new VersionChecker(this);
                checker.start();
            }
        } else {
            this.props.setProperty("autoVersionCheck", "true");
            this.saveProperties();
        }
        reloadAbilityLists();

        boolean displayDPS = Boolean.parseBoolean(this.props.getProperty("displayDPS"));
        boolean displayHPS = Boolean.parseBoolean(this.props.getProperty("displayHPS"));
        if (!displayDPS && !displayHPS) {
            this.props.setProperty("displayDPS", "true");
            this.saveProperties();
        }
        
        class StartThread extends Thread {
            private LiteGui parent;
            public StartThread(LiteGui parent) {
                this.parent = parent;
            }

            @Override
            public void run() {
                this.parent.checkForServer();
            }
        };
        
        if (!this.props.getProperty("combatLogPath").equalsIgnoreCase("<setup>")) {
            if (Boolean.parseBoolean(this.props.getProperty("sendData"))) {
                this.characterID = this.getServer() + File.separator + this.getMainCharacter();
                StartThread st = new StartThread(this);
                st.start();
            }
        } else if (!firstTime) {
            this.characterID = null;
            this.configureNewLogPath();
        }

        if (this.props.getProperty("guiX") != null) {
            this.setBounds(Integer.parseInt(this.props.getProperty("guiX")),
                    Integer.parseInt(this.props.getProperty("guiY")),
                    Integer.parseInt(this.props.getProperty("guiWidth")),
                    Integer.parseInt(this.props.getProperty("guiHeight")));
        }

        this.clearEncounters();

        this.jTable1.setAutoCreateRowSorter(true);
        
    //this.loadRespawnsInZone(this.currentLocation);
    }

    public void addSpellToTimerWindow(HashMap map, String spellName, double multiplier) {
        if (timer == null || !timer.isVisible()) {
            timer = new TimerWindow(map);
            timer.setDefaultCloseOperation(this.DISPOSE_ON_CLOSE);
            timer.setBounds(this.getX() + (this.getWidth() - timer.getWidth()),
                    this.getY() + (this.getHeight() - timer.getHeight()), timer.getWidth(), timer.getHeight());
            if (Boolean.parseBoolean(this.props.getProperty("autoDisplaySpellTimers"))) {
                timer.setVisible(true);
            } else {
                timer.setVisible(false);
            }
            timer.startTimer(spellName, multiplier);
        } else {
            timer.setSpellList(map);
            timer.resetTimer(spellName, multiplier);
        }
    }

    private void showTimerWindow() {
        if (timer == null || !timer.isVisible()) {
            timer = new TimerWindow();
            timer.setDefaultCloseOperation(this.DISPOSE_ON_CLOSE);
            timer.setBounds(this.getX() + (this.getWidth() - timer.getWidth()),
                    this.getY() + (this.getHeight() - timer.getHeight()), timer.getWidth(), timer.getHeight());
            timer.setVisible(true);
        } else {
            timer.setVisible(true);
        }
    }

    Comparator<String> durationComparator = new Comparator<String>() {
        public int compare(String s1, String s2) {
            int rval = 0;
            Duration d1 = new Duration();
            Duration d2 = new Duration();
//            System.out.println("s1:"  + s1 + ", s2: " + s2);
            if (s1.lastIndexOf(":") > s1.indexOf(":")) {
                String[] split = s1.split(":");
                d1.setHour(Short.parseShort(split[0]));
                d1.setMin(Short.parseShort(split[1]));
                d1.setSec(Short.parseShort(split[2]));
            } else {
                String[] split = s1.split(":");
                d1.setMin(Short.parseShort(split[0]));
                d1.setSec(Short.parseShort(split[1]));
            }
            if (s2.lastIndexOf(":") > s2.indexOf(":")) {
                String[] split = s2.split(":");
                d2.setHour(Short.parseShort(split[0]));
                d2.setMin(Short.parseShort(split[1]));
                d2.setSec(Short.parseShort(split[2]));
            } else {
                String[] split = s2.split(":");
                d2.setMin(Short.parseShort(split[0]));
                d2.setSec(Short.parseShort(split[1]));
            }

            if (d2.getDurationInSeconds() > d1.getDurationInSeconds()) {
                rval = -1;
            } else if (d2.getDurationInSeconds() < d1.getDurationInSeconds()) {
                rval = 1;
            }
            return rval;
        }
    };

    Comparator<Double> doubleComparator = new Comparator<Double>() {
        public int compare(Double i1, Double i2) {
            int rval = 0;
            if (i2 > i1) {
                rval = -1;
            } else if (i2 < i1) {
                rval = 1;
            }
            return rval;
        }
    };

    Comparator<String> stringToDoubleComparator = new Comparator<String>() {
        public int compare(String s1, String s2) {
            Double d1 = Double.parseDouble(s1.replaceAll(",", "").replaceAll("NaN", "0"));
            Double d2 = Double.parseDouble(s2.replaceAll(",", "").replaceAll("NaN", "0"));
            int rval = 0;
            if (d2 > d1) {
                rval = -1;
            } else if (d2 < d1) {
                rval = 1;
            }
            return rval;
        }
    };

    Comparator<Integer> intComparator = new Comparator<Integer>() {
        public int compare(Integer i1, Integer i2) {
            int rval = 0;
            if (i2 > i1) {
                rval = -1;
            } else if (i2 < i1) {
                rval = 1;
            }
            return rval;
        }
    };

    Comparator<String> stringToIntComparator = new Comparator<String>() {
        public int compare(String s1, String s2) {
            Integer i1 = Integer.parseInt(s1.replaceAll(",", ""));
            Integer i2 = Integer.parseInt(s2.replaceAll(",", ""));
            int rval = 0;
            if (i2 > i1) {
                rval = -1;
            } else if (i2 < i1) {
                rval = 1;
            }
            return rval;
        }
    };
    
    public void sendStartToServer() {
        String tmp = this.props.getProperty("combatLogPath");
        //System.out.println(tmp);
        if (!tmp.equalsIgnoreCase("<setup>")) {
            Line line = new Line("", Line.CONNECT);
            line.setCharacter(this.getMainCharacter());
            line.setServer(this.getServer());
            this.sendData(line);
        }
    }

    public void addDataToTail(Object o) {
        this.combatTail.addDataObject(o);
    //System.out.println(o);
    }

    int currentError = -1;
    public int getError() {
        return this.currentError;
    }
    
    public void setError(int error) {
        this.currentError = error;
    }
    
    public static void throwError(int error) {
        /*
         * 1: Can't find log file
         * 2: Can't connect to server for upgrades
         * 3: Lost connection to log file mid-parse
         * 4: Test msg
         * 5: Parsing error
         * 6: Logging is disabled
         */
        String errorMsg = null;
        switch (error) {
            case 1:
                errorMsg = "There was a problem accessing the log file. Please re-select your log file by clicking File -> Select Character";
                break;
            case 2:
                errorMsg = "Could not connect to the upgrade server; please try again later.";
                break;
            case 3:
                errorMsg = "Lost connection to log file. Parsing stopped.";
                break;
            case 4:
                errorMsg = "This is a test! Do you see me?";
                break;
            case 5:
                errorMsg = "A parsing error ocurred. Click play to restart.";
                break;
            case 6:
                errorMsg = "WAR logging is disabled, but WarCT could not enable it. Please exit WAR if it is running and restart WarCT to enable logging.";
                break;
            default:
                break;
        }
        JOptionPane.showMessageDialog(null, errorMsg, "Error!", JOptionPane.ERROR_MESSAGE);
    }

    void copy(File src, File dst) throws IOException {
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dst);

        // Transfer bytes from in to out
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }

    public void setRestart(boolean restart) {
        this.restart = restart;
    }

    public String getVersion() {
        return this.version;
    }

    public String checkVersion(boolean startup) {
        String rval = null;
        //LCTClient client = new LCTClient();
        try {
            this.jLabel2.setText("Checking for new version...");
            String urlVersion = this.getVersionFromURL();
            if (this.getVersion().equalsIgnoreCase(urlVersion)) {
                if (!startup) {
                    JOptionPane.showMessageDialog(this, "LCT is up to date.", "LCT Version", JOptionPane.INFORMATION_MESSAGE);
                }
                this.jLabel2.setText("LCT is up to date.");
            } else {
                JOptionPane.showMessageDialog(this, "New version available! Click Download to get version " + urlVersion + ".", "LCT Version", JOptionPane.INFORMATION_MESSAGE);
                rval = urlVersion;
                if (startup) {
                    this.loadNewVersionDownloadWindow(startup, urlVersion);
                }
                this.jLabel2.setText("New Version (" + urlVersion + ") available!");
            }
        } catch (Exception ex) {
            //ex.printStackTrace();
        }
        return rval;
    }

    public void updateZonewideEncounterNode() {
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree.getModel();
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tmpModel.getChild(root, 0);
        node.setUserObject(this.zonewideEncounter);

    }

    public void initializeNewCharacter() {
        this.zonewideDPS = new HashMap();
        root.setUserObject(new Duration());
        this.currentLocation = "Unknown";
    }

    public String getServer() {
        String rval = null;
        String tmp = this.getCombatFileLocation().substring(
                0, this.getCombatFileLocation().lastIndexOf(File.separator + "eq2log_" + this.getMainCharacter()));
        rval = tmp.substring(tmp.lastIndexOf(File.separator) + 1);
        return rval;
    }

    class MenuAction extends AbstractAction {

        private LiteGui parent;

        public MenuAction(String text, LiteGui parentGui) {
            super(text);
            this.parent = parentGui;
        }

        public void actionPerformed(ActionEvent evt) {
            try {
                if (evt.getActionCommand().equalsIgnoreCase("Select Character")) {
                    this.parent.configureNewLogPath();
                } else if (evt.getActionCommand().equalsIgnoreCase("Options")) {
                    OptionsWindow options = new OptionsWindow(this.parent);
                    options.setBounds(this.parent.getX() + (this.parent.getWidth() / 2) - (options.getWidth() / 2),
                            this.parent.getY() + (this.parent.getHeight() / 2) - (options.getHeight() / 2),
                            options.getWidth(), options.getHeight());
                    options.setVisible(true);
                } else if (evt.getActionCommand().equalsIgnoreCase("Test")) {
                    test tester = new test(this.parent.combatLogFileLocation);
                    tester.start();
                } else if (evt.getActionCommand().equalsIgnoreCase("Validate Character")) {
                    SubmitCharacterWindow submit = new SubmitCharacterWindow(
                            this.parent.getMainCharacter(), this.parent.getServer());
                    submit.setBounds(this.parent.getX() + (this.parent.getWidth() / 2) - (submit.getWidth() / 2),
                            this.parent.getY() + (this.parent.getHeight() / 2) - (submit.getHeight() / 2),
                            submit.getWidth(), submit.getHeight());
                    submit.setVisible(true);
                } else if (evt.getActionCommand().equalsIgnoreCase("Spell Timer Window")) {
                    this.parent.showTimerWindow();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public TimerWindow getTimerWindow() {
        return this.timer;
    }

    private void populateHistoryTab() {
        root3 = new DefaultMutableTreeNode("History");
        historyTree.setModel(new DefaultTreeModel(root3));

        String historyDir = "history" + File.separator + this.getMainCharacter() + "_" + this.getServer() + "_history" + File.separator;
        File file = new File(historyDir);

        DefaultTreeModel tmpModel = (DefaultTreeModel) historyTree.getModel();
        SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM d, yyyy");
        ArrayList dates = new ArrayList();

        File[] dirs = file.listFiles();
        if (dirs != null) {
            for (int x = 0; x < dirs.length; x++) {
                Date date = null;
                try {
                    date = sdf.parse(dirs[x].getName());
                } catch (ParseException ex) {
                    ex.printStackTrace();
                }
                dates.add(date);
            }

            Collections.sort(dates);

            for (int x = 0; x < dates.size(); x++) {
                DefaultMutableTreeNode node = new DefaultMutableTreeNode(sdf.format((Date) dates.get(x)));
                tmpModel.insertNodeInto(node, root3, 0);
            }

            historyTree.expandRow(0);
        }
    }

    private boolean configureNewLogPath() {
        boolean rval = false;

        class TempThread extends Thread {
            private LiteGui parent;
            public TempThread(LiteGui parent) {
                this.parent = parent;
            }

            @Override
            public void run() {
                LogSelector selector = new LogSelector(this.parent);
                selector.setBounds(this.parent.getX() + (this.parent.getWidth() / 2) - (selector.getWidth() / 2),
                        this.parent.getY() + (this.parent.getHeight() / 2) - (selector.getHeight() / 2),
                        selector.getWidth(), selector.getHeight());
                selector.setVisible(true);
                selector.setAlwaysOnTop(true);
                String logPath = parent.props.getProperty("combatLogPath");
                if (logPath != null && !logPath.equalsIgnoreCase("<setup>") && this.parent.getError() == -1) {
                    String rootDir = logPath.substring(0, logPath.indexOf(File.separator + "logs"));
                    selector.searchForLog(true, rootDir);
                } else {
                    selector.searchForLog(false, null);
                }
                
            }
        }

        TempThread t = new TempThread(this);
        this.jLabel2.setText("Initializing new log file...");
        t.start();

        return rval;
    }

    public void manuallySelectLogFile() {
        JFileChooser jFileChooser = new JFileChooser();
        jFileChooser.setDialogTitle("Select Location of Log File");
//        jFileChooser.setCurrentDirectory(new File("C:\\"));
        int returnVal = jFileChooser.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = jFileChooser.getSelectedFile();
            this.props.setProperty("combatLogPath", file.getAbsolutePath());
            this.combatLogFileLocation = file.getAbsolutePath();
            this.setCombatLogFileName(file.getName());
            saveProperties();
            this.clearEncounters();
            this.createHistoryDirs();

            if (this.combatTail != null) {
                this.combatTail.stopRunning();
            }

//            if (this.systemTail != null) {
//                this.systemTail.stopRunning();
//            }

            this.storeEncounterHistory();
            this.initializeNewCharacter();

            this.combatTail = new Tail(this, Tail.COMBAT_LOG);
            this.combatTail.start();
//            this.systemTail = new Tail(this, Tail.SYSTEM_LOG);
//            this.systemTail.start();
            this.startParse();
        }
    }

    //private boolean logPathUpdated = false; //boolean updated, 
    public void updateLogPath(File file) {
        //File systemLog = new File(absPath.replace("combat.log", "chat.log"));
//        File chatLog = new File(absPath.substring(0, absPath.lastIndexOf("\\") + 1) + "chat.log");
//        File guildLog = new File(absPath.substring(0, absPath.lastIndexOf("\\") + 1) + "guildnews.log");
        
        if (this.getMainCharacter() != null) {
            Line line = new Line("", Line.DISCONNECT);
            line.setCharacter(this.getMainCharacter());
            line.setServer(this.getServer());
            this.sendData(line);
        }
        this.clearEncounters();

        String absPath = file.getAbsolutePath();
        
        this.props.setProperty("combatLogPath", absPath);
        this.props.setProperty("systemLogPath", absPath.replace("combat.log", "chat.log"));
        this.combatLogFileLocation = absPath;
        this.systemLogFileLocation = absPath.replace("combat.log", "chat.log");
        this.setCombatLogFileName(file.getName());
        saveProperties();
        
//        if (this.guildTail != null) {
//            this.guildTail.stopRunning();
//        }
//        
//        if (this.chatTail != null) {
//            this.chatTail.stopRunning();
//        }

//        if (this.systemTail != null) {
//            this.systemTail.stopRunning();
//        }

        if (this.combatTail != null) {
            this.combatTail.stopRunning();
        }
        this.storeEncounterHistory();
        this.initializeNewCharacter();
        this.combatTail = new Tail(this, Tail.COMBAT_LOG);
        this.combatTail.start();
//        this.systemTail = new Tail(this, Tail.SYSTEM_LOG);
//        this.systemTail.start();
        this.characterID = this.getServer() + File.separator + this.getMainCharacter();
        this.startParse();
        
        //this.sendData("::startid::" + this.characterID);
        if (this.getMainCharacter() != null) {
            if (!this.checkForServer()) {
                Line line = new Line("", Line.CONNECT);
                line.setCharacter(this.getMainCharacter());
                line.setServer(this.getServer());
                this.sendData(line);
            }
        }
        this.createHistoryDirs();
    }

    public boolean runningOnSamePC() {
        return this.sameComputer;
    }

    private void saveProperties() {
        try {
            FileOutputStream out = new FileOutputStream(propFile);
            this.props.store(out, "updated");
            out.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void initDefaultProperties() {
        configureNewLogPath();

        try {
            HashMap map = new HashMap();
            map.put("always", new ArrayList());
            map.put("never", new ArrayList());
            FileOutputStream fos = new FileOutputStream("list.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(map);
            fos.close();
            oos.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        String pathCheck = null;
        pathCheck = this.props.getProperty("combatLogPath");
        if (pathCheck != null) {
            if (this.props.getProperty("combatLogPath").contains("\\\\")) {
                this.isNetwork = true;
                this.props.setProperty("network", "true");
            } else {
                this.isNetwork = false;
                this.props.setProperty("network", "false");
            }
        } else {
            this.props.setProperty("combatLogPath", "<setup>");
        }

        this.props.setProperty("checkForNewProxyBoolean", "false");
        this.props.setProperty("checkForNewProxyServer", "");
        this.props.setProperty("checkForNewProxyPort", "8080");
        this.props.setProperty("autoVersionCheck", "true");
        this.props.setProperty("secondsToWaitToEndEncounter", "3");
        this.props.setProperty("maxPieGraph", "20");
        this.props.setProperty("respawnPopup", "false");
        this.props.setProperty("respawnBeep", "false");
        this.props.setProperty("eq2OnSamePC", !this.isNetwork + "");

        String path = null;
        if (!this.isNetwork && pathCheck != null) {
            String tmpPath = this.combatLogFileLocation.substring(0, this.combatLogFileLocation.lastIndexOf(File.separator));
            path = tmpPath.substring(0, tmpPath.lastIndexOf(File.separator) + 1);
            tmpPath = path.substring(0, path.lastIndexOf(File.separator));
            path = tmpPath.substring(0, tmpPath.lastIndexOf(File.separator) + 1);
        } else {
            path = "";
        }
        this.props.setProperty("doFileCommandsPath", path);
        this.props.setProperty("dpsParsePrefix", "s");
        this.props.setProperty("healParsePrefix", "s");
        this.props.setProperty("displayHPS", "false");
        this.props.setProperty("displayDPS", "true");
        this.props.setProperty("fontName", "Arial");
        this.props.setProperty("fontSize", "11");

        saveProperties();
    }

    public void propertiesUpdated() {
        this.loadProperties();
    }

    private boolean loadProperties() {
        boolean rval = false;
        try {
            props.load(new FileInputStream(new File(propFile)));
            this.propsUpdated = false;
            rval = true;
        } catch (FileNotFoundException ex) {
            this.initDefaultProperties();
            rval = false;
        //ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return rval;
    }

    private void createHistoryDirs() {
        String dir = "history" + File.separator + this.getMainCharacter() + "_" + this.getServer() + "_history" + File.separator;
        File checkDir = new File(dir);
        if (!checkDir.exists()) {
            checkDir.mkdirs();
        }
    }

    public void storeEncounterHistory() {
        SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM d, yyyy");
        try {
            if (this.encounterHistory.size() > 0) {
                Encounter encounter = (Encounter) this.encounterHistory.get(0);
                long id = encounter.getStartAsDate().getTime();
                String dir = "history" + File.separator + this.getMainCharacter() + "_" + this.getServer() + "_history" + File.separator;
                String toStoreStr = dir + sdf.format(id) + File.separator +
                        (Boolean.parseBoolean(this.props.getProperty("zoneClear")) ? this.currentLocation.replaceAll(":", "-") : "Unknown Zones") + File.separator;
//                System.out.println(historyFile);

                File checkDir = new File(toStoreStr);
                if (!checkDir.exists()) {
                    checkDir.mkdirs();
                }

                toStoreStr += "history.dat";
                File toStore = new File(toStoreStr);

                if (!toStore.exists()) {
                    toStore.createNewFile();
                    FileOutputStream fos = new FileOutputStream(toStore);
                    ObjectOutputStream objOut = new ObjectOutputStream(fos);
                    objOut.writeObject(new HashMap());
                    fos.close();
                    objOut.close();
                }
                // Read from disk using FileInputStream.
                FileInputStream f_in = new FileInputStream(toStore);

                // Read object using ObjectInputStream.
                ObjectInputStream obj_in = new ObjectInputStream(f_in);

                // Read an object.
                Object obj = obj_in.readObject();
                HashMap history = (HashMap) obj;

                //System.out.println("Encounter history (memory) size = " + this.encounterHistory.size());
                for (int x = 0; x < this.encounterHistory.size(); x++) {
                    encounter = (Encounter) this.encounterHistory.get(x);
                    id = encounter.getStartAsDate().getTime();
                    if (!history.containsKey(id)) {
                        history.put(id, encounter);
                    }
                }
                id = 999999999999999999L;
                Encounter previousZonewide = (Encounter) history.get(id);
                if (previousZonewide != null) {
                    previousZonewide.addEncounter(this.zonewideEncounter, this.zonewideEncounter.getEncounterDuration());
                } else {
                    previousZonewide = this.zonewideEncounter;
                }
                history.put(id, previousZonewide);

                FileOutputStream fos = new FileOutputStream(toStoreStr);
                ObjectOutputStream objOut = new ObjectOutputStream(fos);
                objOut.writeObject(history);
                fos.close();
                objOut.close();
                //this.zonewideEncounter = new Encounter(this.getMainCharacter(), true);
                this.zonewideEncounter = null;
                this.encounterHistory = new ArrayList();
                this.storedEncounterHistory = new HashMap();
                System.gc();
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    public void setCurrentLocation(String location) {
        jTabbedPane1.setTitleAt(0, location);
        
        if (Boolean.parseBoolean(this.props.getProperty("zoneClear"))) {
            this.zonewideDPS = new HashMap();
            //this.zonewideDuration = new Duration();
            this.root.setUserObject(new Duration());
            if (!this.propsUpdated) {
                this.saveProperties();
            }
            this.clearEncounters();
            if (this.encounterHistory.size() > 0) {
                this.storeEncounterHistory();
            }

            this.saveProperties();
            System.gc();
        }
        this.currentLocation = location.trim();
        this.props.setProperty("currentZone", this.currentLocation);
    }

    public void setArchiveFilePath(String archivePath) {
        this.archiveFilePath = archivePath;
    }

    public String getArchiveFilePath() {
        return this.archiveFilePath;
    }

    public String getCombatFileLocation() {
        return this.combatLogFileLocation;
    }

    public void setCombatFileLocation(String fileLocation) {
        this.combatLogFileLocation = fileLocation;
    }

    public void setCombatLogFileName(String fileName) {
        this.fileName = fileName;
        this.setTitle("Lite Combat Tracker for Everquest 2 (v" + version + ") - " + this.getMainCharacter());
    }

    public String getMainCharacter() {
        String rval = null;
        try {
            String fileLoc = this.getCombatFileLocation();
            String tmp = fileLoc.substring(fileLoc.lastIndexOf(File.separator) + 1);
            rval = tmp.substring(tmp.indexOf("_") + 1, tmp.lastIndexOf("."));
        } catch (StringIndexOutOfBoundsException ex) {
            rval = "";
        } catch (NullPointerException ex) {
            //nothing
        }
        return rval;
    }

    public static String getFileName() {
        return fileName;
    }

    public String getCurrentZone() {
        return this.currentLocation;
    }

    public boolean fileLocationIsNetwork() {
        return this.isNetwork;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPopupMenu1 = new javax.swing.JPopupMenu();
        jMenuItem1 = new javax.swing.JMenuItem();
        jPopupMenu2 = new javax.swing.JPopupMenu();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenuItem4 = new javax.swing.JMenuItem();
        jMenuItem20 = new javax.swing.JMenuItem();
        jPopupMenu3 = new javax.swing.JPopupMenu();
        jMenuItem3 = new javax.swing.JMenuItem();
        jPopupMenu4 = new javax.swing.JPopupMenu();
        jMenuItem5 = new javax.swing.JMenuItem();
        jCheckBoxMenuItem1 = new javax.swing.JCheckBoxMenuItem();
        jPopupMenu5 = new javax.swing.JPopupMenu();
        jCheckBoxMenuItem2 = new javax.swing.JCheckBoxMenuItem();
        jCheckBoxMenuItem3 = new javax.swing.JCheckBoxMenuItem();
        jPopupMenu6 = new javax.swing.JPopupMenu();
        jMenuItem6 = new javax.swing.JMenuItem();
        jMenuItem7 = new javax.swing.JMenuItem();
        jMenuItem22 = new javax.swing.JMenuItem();
        jPopupMenu7 = new javax.swing.JPopupMenu();
        jMenuItem10 = new javax.swing.JMenuItem();
        jMenuItem11 = new javax.swing.JMenuItem();
        jMenuItem12 = new javax.swing.JMenuItem();
        jPopupMenu8 = new javax.swing.JPopupMenu();
        jMenuItem13 = new javax.swing.JMenuItem();
        jMenuItem14 = new javax.swing.JMenuItem();
        jMenuItem15 = new javax.swing.JMenuItem();
        jMenuItem21 = new javax.swing.JMenuItem();
        jPopupMenu9 = new javax.swing.JPopupMenu();
        jMenuItem16 = new javax.swing.JMenuItem();
        jPopupMenu10 = new javax.swing.JPopupMenu();
        jMenuItem17 = new javax.swing.JMenuItem();
        jMenuItem18 = new javax.swing.JMenuItem();
        jMenuItem19 = new javax.swing.JMenuItem();
        jPopupMenu11 = new javax.swing.JPopupMenu();
        jMenuItem8 = new javax.swing.JMenuItem();
        layeredPane = new javax.swing.JLayeredPane();
        jLabel1 = new javax.swing.JLabel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        //jTabbedPane1.setTitleAt(2, "Encounter History");
        jScrollPane = new javax.swing.JScrollPane();
        zonewide = new DefaultMutableTreeNode("Zonewide");
        root = new DefaultMutableTreeNode(new Duration());
        jTree = new JTree(root);
        jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
        jScrollPane2 = new javax.swing.JScrollPane();
        root2 = new DefaultMutableTreeNode("Not In Group");
        jTree1 = new JTree(root2);
        jScrollPane5 = new javax.swing.JScrollPane();
        root3 = new DefaultMutableTreeNode("History");
        historyTree = new JTree(root3);
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jPanel1 = new javax.swing.JPanel();
        Icon pause = new ImageIcon("pause2.PNG");
        group = new ButtonGroup();
        togglePause = new JToggleButton(pause);
        togglePause.getModel().setGroup(group);
        togglePause.setFocusPainted(false);
        Icon stop = new ImageIcon("stop2.PNG");
        toggleStop = new JToggleButton(stop);
        toggleStop.getModel().setGroup(group);
        toggleStop.setFocusPainted(false);
        Icon start = new ImageIcon("start2.PNG");
        toggleStart = new JToggleButton(start);
        toggleStart.getModel().setGroup(group);
        toggleStart.setFocusPainted(false);
        jLabel2 = new javax.swing.JLabel();
        jMenuBar = new javax.swing.JMenuBar();
        jMenu = new javax.swing.JMenu();
        jMenuItem9 = new javax.swing.JMenuItem();

        jPopupMenu1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPopupMenu1MouseClicked(evt);
            }
        });

        jMenuItem1.setText("Item");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        jPopupMenu1.add(jMenuItem1);

        jPopupMenu2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPopupMenu2MouseClicked(evt);
            }
        });

        jMenuItem2.setText("Item");
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem2ActionPerformed(evt);
            }
        });
        jPopupMenu2.add(jMenuItem2);

        jMenuItem4.setText("Item");
        jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem4ActionPerformed(evt);
            }
        });
        jPopupMenu2.add(jMenuItem4);

        jMenuItem20.setText("jMenuItem20");
        jMenuItem20.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem20ActionPerformed(evt);
            }
        });
        jPopupMenu2.add(jMenuItem20);

        jPopupMenu3.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPopupMenu3MouseClicked(evt);
            }
        });

        jMenuItem3.setText("Item");
        jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem3ActionPerformed(evt);
            }
        });
        jPopupMenu3.add(jMenuItem3);

        jMenuItem5.setText("Delete");
        jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem5ActionPerformed(evt);
            }
        });
        jPopupMenu4.add(jMenuItem5);

        jCheckBoxMenuItem1.setText("Reset When Killed");
        jCheckBoxMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCheckBoxMenuItem1ActionPerformed(evt);
            }
        });
        jPopupMenu4.add(jCheckBoxMenuItem1);

        jCheckBoxMenuItem2.setText("Always Include on Pie Graphs");
        jCheckBoxMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCheckBoxMenuItem2ActionPerformed(evt);
            }
        });
        jPopupMenu5.add(jCheckBoxMenuItem2);

        jCheckBoxMenuItem3.setText("Never Include on Pie Graphs");
        jCheckBoxMenuItem3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCheckBoxMenuItem3ActionPerformed(evt);
            }
        });
        jPopupMenu5.add(jCheckBoxMenuItem3);

        jMenuItem6.setText("Copy Heal Parse");
        jMenuItem6.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem6ActionPerformed(evt);
            }
        });
        jPopupMenu6.add(jMenuItem6);

        jMenuItem7.setText("Copy Damage Parse");
        jMenuItem7.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem7ActionPerformed(evt);
            }
        });
        jPopupMenu6.add(jMenuItem7);

        jMenuItem22.setText("Generate Avoidance Report");
        jMenuItem22.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem22ActionPerformed(evt);
            }
        });
        jPopupMenu6.add(jMenuItem22);

        jPopupMenu7.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPopupMenu7MouseClicked(evt);
            }
        });

        jMenuItem10.setLabel("Copy Damage Parse");
        jMenuItem10.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem10ActionPerformed(evt);
            }
        });
        jPopupMenu7.add(jMenuItem10);

        jMenuItem11.setLabel("Copy Heal Parse");
        jMenuItem11.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem11ActionPerformed(evt);
            }
        });
        jPopupMenu7.add(jMenuItem11);

        jMenuItem12.setText("Show Attendance Call");
        jMenuItem12.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem12ActionPerformed(evt);
            }
        });
        jPopupMenu7.add(jMenuItem12);

        jMenuItem13.setText("Copy Heal Parse");
        jMenuItem13.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem13ActionPerformed(evt);
            }
        });
        jPopupMenu8.add(jMenuItem13);

        jMenuItem14.setText("Copy Damage Parse");
        jMenuItem14.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem14ActionPerformed(evt);
            }
        });
        jPopupMenu8.add(jMenuItem14);

        jMenuItem15.setText("Show Attendance Call");
        jMenuItem15.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem15ActionPerformed(evt);
            }
        });
        jPopupMenu8.add(jMenuItem15);

        jMenuItem21.setText("Generate Avoidance Report");
        jMenuItem21.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem21ActionPerformed(evt);
            }
        });
        jPopupMenu8.add(jMenuItem21);

        jMenuItem16.setText("Merge Encounters");
        jMenuItem16.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem16ActionPerformed(evt);
            }
        });
        jPopupMenu9.add(jMenuItem16);

        jPopupMenu10.setEnabled(false);

        jMenuItem17.setText("Join");
        jMenuItem17.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem17ActionPerformed(evt);
            }
        });
        jPopupMenu10.add(jMenuItem17);

        jMenuItem18.setText("Leave");
        jMenuItem18.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem18ActionPerformed(evt);
            }
        });
        jPopupMenu10.add(jMenuItem18);

        jMenuItem19.setText("Create");
        jMenuItem19.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem19ActionPerformed(evt);
            }
        });
        jPopupMenu10.add(jMenuItem19);

        jMenuItem8.setText("Clear Encounters");
        jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem8ActionPerformed(evt);
            }
        });
        jPopupMenu11.add(jMenuItem8);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowFocusListener(new java.awt.event.WindowFocusListener() {
            public void windowGainedFocus(java.awt.event.WindowEvent evt) {
                formWindowGainedFocus(evt);
            }
            public void windowLostFocus(java.awt.event.WindowEvent evt) {
                formWindowLostFocus(evt);
            }
        });
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosed(java.awt.event.WindowEvent evt) {
                formWindowClosed(evt);
            }
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });
        addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                formComponentResized(evt);
            }
        });
        addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                formFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                formFocusLost(evt);
            }
        });

        layeredPane.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jLabel1.setBounds(0, 0, 560, 430);
        layeredPane.add(jLabel1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        jTabbedPane1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jTabbedPane1KeyPressed(evt);
            }
        });
        jTabbedPane1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTabbedPane1MouseClicked(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTabbedPane1MouseReleased(evt);
            }
        });

        jTree.setExpandsSelectedPaths(false);
        jTree.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTreeMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jTreeMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTreeMouseReleased(evt);
            }
        });
        jTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                jTreeValueChanged(evt);
            }
        });
        jScrollPane.setViewportView(jTree);

        jTabbedPane1.addTab("tab1", jScrollPane);

        jTree1.setExpandsSelectedPaths(false);
        jTree1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jTree1MousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTree1MouseReleased(evt);
            }
        });
        jTree1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTree1KeyReleased(evt);
            }
        });
        jScrollPane2.setViewportView(jTree1);

        jTabbedPane1.addTab("tab2", jScrollPane2);

        historyTree.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                historyTreeMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                historyTreeMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                historyTreeMouseReleased(evt);
            }
        });
        jScrollPane5.setViewportView(historyTree);

        jTabbedPane1.addTab("tab3", jScrollPane5);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Combatant Name", "Allied Status", "Duration", "Encounter DPS", "Damage Dealt", "Healing Done", "Damage Taken"
            }
        ) {
            boolean[] canEdit = new boolean [] {
                false, false, false, false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        //final Object columnNames[] = { "Combatant Name", "Allied Status", "Duration", "Extended DPS", "Damage Dealt", "Amount Healed", "Damage Taken" };

        //model = new DefaultTableModel(columnNames, 0);

        //jTable1 = new JTable(model);

        //jTable1.setAutoCreateColumnsFromModel(false);
        jTable1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTable1MouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(jTable1);

        jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        togglePause.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                togglePauseActionPerformed(evt);
            }
        });

        toggleStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toggleStopActionPerformed(evt);
            }
        });

        toggleStart.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toggleStartActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .add(2, 2, 2)
                .add(toggleStart, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 24, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(togglePause, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 24, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(toggleStop, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 24, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                .add(toggleStart, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(togglePause, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(toggleStop, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
        );

        jMenu.setText("File");
        jMenu.addMenuListener(new javax.swing.event.MenuListener() {
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
            }
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                jMenuMenuSelected(evt);
            }
        });

        jMenuItem9.setText("Check For New Versions");
        jMenuItem9.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem9ActionPerformed(evt);
            }
        });
        jMenu.add(jMenuItem9);

        jMenuBar.add(jMenu);

        setJMenuBar(jMenuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .add(2, 2, 2)
                        .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(18, 18, 18)
                        .add(jLabel2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 201, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 309, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(layeredPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 560, Short.MAX_VALUE)
                    .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 560, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                            .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(jLabel2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 607, Short.MAX_VALUE))
                    .add(layout.createSequentialGroup()
                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 241, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(5, 5, 5)
                        .add(layeredPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)))
                .addContainerGap())
        );

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-893)/2, (screenSize.height-699)/2, 893, 699);
    }// </editor-fold>//GEN-END:initComponents
    private void jMenuItem15ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem15ActionPerformed
        
    }//GEN-LAST:event_jMenuItem15ActionPerformed

    private void jMenuItem14ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem14ActionPerformed
        ArrayList historyHealers = new ArrayList();
        ArrayList historyDPSers = new ArrayList();

        ArrayList combatants = this.lastHistoryClicked.getCombatants();

        totalExtendedDPS = 0;
        totalHealing = 0;

        ArrayList tmpHealers = new ArrayList();

        String combatantName;
        DecimalFormat df = new DecimalFormat("###.##");

        int counter = 0;
        for (int x = 0; x < combatants.size(); x++) {
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();

            if (this.lastHistoryClicked.isAlly(combatantName)) {
                double dps = combatant.getExtendedDPS();
                if (dps > 0) {
                    totalExtendedDPS += dps;
                    historyDPSers.add(combatantName + "  |  " + df.format(dps) + "\r\n");
                }

                double healing = combatant.getTotalHealingDone();
                if (healing > 0) {
                    totalHealing += healing;
                    tmpHealers.add(combatantName + "," + healing);
                }
                counter++;
            }
        }

        Collections.sort(historyDPSers, parses);

        ArrayList tmpHealed = new ArrayList();
        for (int x = 0; x < tmpHealers.size(); x++) {
            String tmp = (String) tmpHealers.get(x);
            double tmpHeal = Double.parseDouble(tmp.substring(tmp.indexOf(",") + 1));
            tmpHealed.add(tmpHeal);
        }

        Collections.sort(tmpHealed, Collections.reverseOrder());

        df = new DecimalFormat("#,###,###.##");
        String zonewide = null;
        boolean zwAvailable = false;
        if (this.lastHistoryClicked.toString().equalsIgnoreCase("Zonewide")) {
            zonewide = "Zonewide";
            zwAvailable = true;
        } else {
            zonewide = "Encounter";
        }

        historyDPSers.add(0, zonewide + " DPS:  (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - {" + df.format(totalExtendedDPS) + "} - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]\r\n");
        historyHealers.add(zonewide + " Healing: (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]");

        for (int x = 0; x < tmpHealed.size(); x++) {
            double amt = (Double) tmpHealed.get(x);

            String tmpAmt = amt + "";
            for (int y = 0; y < tmpHealers.size(); y++) {
                String temp = (String) tmpHealers.get(y);

                String name = temp.substring(0, temp.indexOf(","));
                if (x < 8) {
                    if (name.length() > _longest) {
                        _longest = name.length();
                    }
                }

                if (temp.contains(tmpAmt)) {
                    historyHealers.add(temp.replaceAll(",", " | "));
                //System.out.println(temp.replaceAll(",", " | "));
                }
            }
        }

        int longest = 0;
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                String name = line.substring(0, line.indexOf("  "));
                if (x < 8) {
                    int length = name.length();
                    if (length > longest) {
                        longest = length;
                    }
                }
            }
        }

        StringBuffer parse = new StringBuffer();
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            String name = line.substring(0, line.indexOf("  ")).trim();
            String rest = line.substring(line.indexOf("  ")).trim();

            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                while ((longest - name.length()) > 0) {
                    name += " ";
                }
            }
            String write = this.props.getProperty("dpsParsePrefix") + " " + name + " " + rest + "\r\n";
            //bw.write(write);
            parse.append(write);

            if (x == 7) {
                x = historyDPSers.size();
            }
        }

        parses.setHistoryDPSParse(parse);

        parse = new StringBuffer();

        //bw = new BufferedWriter(new FileWriter(healOutput));
        for (int x = 0; x < historyHealers.size(); x++) {
            String line = (String) historyHealers.get(x);
            String name = line.substring(0, line.indexOf(" ")).trim();
            String rest = line.substring(line.indexOf(" "));
            double amount = 0;
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                amount = Double.parseDouble(line.substring(line.indexOf("|") + 2));
                //System.out.println(line + ", " + amount + ", " + totalHealing);
                while ((_longest - name.length()) > 0) {
                    name += " ";
                }
            }
            double mult = 100;
            String heal = this.props.getProperty("healParsePrefix") + " " + name + rest +
                    (!line.contains("Encounter") ? " | " + df.format(((amount / totalHealing) * mult)) + "%" : "") + "\r\n";
            //bw.write(heal);
            parse.append(heal);
            if (x == 7) {
                x = historyHealers.size();
            }
        }
        parses.setHistoryHealParse(parse);

        this.exportParse(0, true, false, true);
    }//GEN-LAST:event_jMenuItem14ActionPerformed

    private void jMenuItem13ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem13ActionPerformed
        ArrayList historyHealers = new ArrayList();
        ArrayList historyDPSers = new ArrayList();

        ArrayList combatants = this.lastHistoryClicked.getCombatants();

        totalExtendedDPS = 0;
        totalHealing = 0;

        ArrayList tmpHealers = new ArrayList();

        String combatantName;
        DecimalFormat df = new DecimalFormat("###.##");
        int counter = 0;
        for (int x = 0; x < combatants.size(); x++) {
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();

            if (this.lastHistoryClicked.isAlly(combatantName)) {
                double dps = combatant.getExtendedDPS();
                if (dps > 0) {
                    totalExtendedDPS += dps;
                    historyDPSers.add(combatantName + "  |  " + df.format(dps) + "\r\n");
                }

                double healing = combatant.getTotalHealingDone();
                if (healing > 0) {
                    totalHealing += healing;
                    tmpHealers.add(combatantName + "," + healing);
                }
                counter++;
            }
        }

        Collections.sort(historyDPSers, parses);

        ArrayList tmpHealed = new ArrayList();
        for (int x = 0; x < tmpHealers.size(); x++) {
            String tmp = (String) tmpHealers.get(x);
            double tmpHeal = Double.parseDouble(tmp.substring(tmp.indexOf(",") + 1));
            tmpHealed.add(tmpHeal);
        }

        Collections.sort(tmpHealed, Collections.reverseOrder());

        df = new DecimalFormat("#,###,###.##");
        String zonewide = null;
        boolean zwAvailable = false;
        if (this.lastHistoryClicked.toString().equalsIgnoreCase("Zonewide")) {
            zonewide = "Zonewide";
            zwAvailable = true;
        } else {
            zonewide = "Encounter";
        }

        historyDPSers.add(zonewide + " DPS:  (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - {" + df.format(totalExtendedDPS) + "} - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]\r\n");
        historyHealers.add(zonewide + " Healing: (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]");


        for (int x = 0; x < tmpHealed.size(); x++) {
            double amt = (Double) tmpHealed.get(x);

            String tmpAmt = amt + "";
            for (int y = 0; y < tmpHealers.size(); y++) {
                String temp = (String) tmpHealers.get(y);

                String name = temp.substring(0, temp.indexOf(","));
                if (x < 8) {
                    if (name.length() > _longest) {
                        _longest = name.length();
                    }
                }

                if (temp.contains(tmpAmt)) {
                    historyHealers.add(temp.replaceAll(",", " | "));
                //System.out.println(temp.replaceAll(",", " | "));
                }
            }
        }

        int longest = 0;
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                String name = line.substring(0, line.indexOf("  "));
                if (x < 8) {
                    int length = name.length();
                    if (length > longest) {
                        longest = length;
                    }
                }
            }
        }

        StringBuffer parse = new StringBuffer();
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            String name = line.substring(0, line.indexOf("  ")).trim();
            String rest = line.substring(line.indexOf("  ")).trim();

            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                while ((longest - name.length()) > 0) {
                    name += " ";
                }
            }
            String write = this.props.getProperty("dpsParsePrefix") + " " + name + " " + rest + "\r\n";
            //bw.write(write);
            parse.append(write);

            if (x == 7) {
                x = historyDPSers.size();
            }
        }
        //bw.close();
        parses.setHistoryDPSParse(parse);

        parse = new StringBuffer();

        //bw = new BufferedWriter(new FileWriter(healOutput));
        for (int x = 0; x < historyHealers.size(); x++) {
            String line = (String) historyHealers.get(x);
            String name = line.substring(0, line.indexOf(" ")).trim();
            String rest = line.substring(line.indexOf(" "));
            double amount = 0;
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                amount = Double.parseDouble(line.substring(line.indexOf("|") + 2));
                //System.out.println(line + ", " + amount + ", " + totalHealing);
                while ((_longest - name.length()) > 0) {
                    name += " ";
                }
            }
            double mult = 100;
            String heal = this.props.getProperty("healParsePrefix") + " " + name + rest +
                    (!line.contains("Encounter") ? " | " + df.format(((amount / totalHealing) * mult)) + "%" : "") + "\r\n";
            //bw.write(heal);
            parse.append(heal);
            if (x == 7) {
                x = historyHealers.size();
            }
        }
        parses.setHistoryHealParse(parse);

        this.exportParse(0, false, false, true);
    }//GEN-LAST:event_jMenuItem13ActionPerformed

    private void jMenuItem12ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem12ActionPerformed
        
    }//GEN-LAST:event_jMenuItem12ActionPerformed

    private void jPopupMenu7MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPopupMenu7MouseClicked
// TODO add your handling code here:
    }//GEN-LAST:event_jPopupMenu7MouseClicked

    private void jMenuItem11ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem11ActionPerformed
        if (popupClicked instanceof Encounter && rowClicked > 1) {
            this.exportParse(rowClicked - 2, false, false, false);
        } else if (popupClicked instanceof Encounter && rowClicked == 1) {
            this.exportParse(rowClicked - 2, false, true, false);
        }
    }//GEN-LAST:event_jMenuItem11ActionPerformed

    private void jMenuItem10ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem10ActionPerformed
        if (popupClicked instanceof Encounter && rowClicked > 1) {
            this.exportParse(rowClicked - 2, true, false, false);
        } else if (popupClicked instanceof Encounter && rowClicked == 1) {
            this.exportParse(rowClicked - 2, true, true, false);
        }
    }//GEN-LAST:event_jMenuItem10ActionPerformed

    private void jMenuItem9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem9ActionPerformed
        String urlVersion = checkVersion(false);
        if (urlVersion != null) {
            this.loadNewVersionDownloadWindow(false, urlVersion);
        }
    }//GEN-LAST:event_jMenuItem9ActionPerformed

    public void loadNewVersionDownloadWindow(boolean startup, String urlVersion) {
        GetNewVersion checkVer = new GetNewVersion(this, startup, urlVersion);
        checkVer.setDefaultCloseOperation(this.DISPOSE_ON_CLOSE);
        checkVer.setBounds(this.getX() + (this.getWidth() / 2) - (checkVer.getWidth() / 2),
                this.getY() + (this.getHeight() / 2) - (checkVer.getHeight() / 2),
                checkVer.getWidth(), checkVer.getHeight());
        checkVer.setVisible(true);
    }

    private void jMenuItem7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem7ActionPerformed

        ArrayList historyHealers = new ArrayList();
        ArrayList historyDPSers = new ArrayList();

        ArrayList combatants = this.lastHistoryClicked.getCombatants();

        totalExtendedDPS = 0;
        totalHealing = 0;

        ArrayList tmpHealers = new ArrayList();

        String combatantName;
        DecimalFormat df = new DecimalFormat("###.##");

        int counter = 0;
        for (int x = 0; x < combatants.size(); x++) {
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();

            if (this.lastHistoryClicked.isAlly(combatantName)) {
                double dps = combatant.getExtendedDPS();
                if (dps > 0) {
                    totalExtendedDPS += dps;
                    historyDPSers.add(combatantName + "  |  " + df.format(dps) + "\r\n");
                }

                double healing = combatant.getTotalHealingDone();
                if (healing > 0) {
                    totalHealing += healing;
                    tmpHealers.add(combatantName + "," + healing);
                }
                counter++;
            }
        }

        Collections.sort(historyDPSers, parses);

        ArrayList tmpHealed = new ArrayList();
        for (int x = 0; x < tmpHealers.size(); x++) {
            String tmp = (String) tmpHealers.get(x);
            double tmpHeal = Double.parseDouble(tmp.substring(tmp.indexOf(",") + 1));
            tmpHealed.add(tmpHeal);
        }

        Collections.sort(tmpHealed, Collections.reverseOrder());

        df = new DecimalFormat("#,###,###.##");
        String zonewide = null;
        boolean zwAvailable = false;
        if (this.lastHistoryClicked.toString().equalsIgnoreCase("Zonewide")) {
            zonewide = "Zonewide";
            zwAvailable = true;
        } else {
            zonewide = "Encounter";
        }

//        try {
//            zwAvailable = this.lastHistoryClicked.isZonewide();
//        } catch (Exception e) {
//            // nothing
//        }

        historyDPSers.add(0, zonewide + " DPS:  (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - {" + df.format(totalExtendedDPS) + "} - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]\r\n");
        historyHealers.add(zonewide + " Healing: (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]");

        for (int x = 0; x < tmpHealed.size(); x++) {
            double amt = (Double) tmpHealed.get(x);

            String tmpAmt = amt + "";
            for (int y = 0; y < tmpHealers.size(); y++) {
                String temp = (String) tmpHealers.get(y);

                String name = temp.substring(0, temp.indexOf(","));
                if (x < 8) {
                    if (name.length() > _longest) {
                        _longest = name.length();
                    }
                }

                if (temp.contains(tmpAmt)) {
                    historyHealers.add(temp.replaceAll(",", " | "));
                //System.out.println(temp.replaceAll(",", " | "));
                }
            }
        }

        int longest = 0;
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                String name = line.substring(0, line.indexOf("  "));
                if (x < 8) {
                    int length = name.length();
                    if (length > longest) {
                        longest = length;
                    }
                }
            }
        }

        StringBuffer parse = new StringBuffer();
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            String name = line.substring(0, line.indexOf("  ")).trim();
            String rest = line.substring(line.indexOf("  ")).trim();

            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                while ((longest - name.length()) > 0) {
                    name += " ";
                }
            }
            String write = this.props.getProperty("dpsParsePrefix") + " " + name + " " + rest + "\r\n";
            //bw.write(write);
            parse.append(write);

            if (x == 7) {
                x = historyDPSers.size();
            }
        }

        parses.setHistoryDPSParse(parse);

        parse = new StringBuffer();

        //bw = new BufferedWriter(new FileWriter(healOutput));
        for (int x = 0; x < historyHealers.size(); x++) {
            String line = (String) historyHealers.get(x);
            String name = line.substring(0, line.indexOf(" ")).trim();
            String rest = line.substring(line.indexOf(" "));
            double amount = 0;
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                amount = Double.parseDouble(line.substring(line.indexOf("|") + 2));
                //System.out.println(line + ", " + amount + ", " + totalHealing);
                while ((_longest - name.length()) > 0) {
                    name += " ";
                }
            }
            double mult = 100;
            String heal = this.props.getProperty("healParsePrefix") + " " + name + rest +
                    (!line.contains("Encounter") ? " | " + df.format(((amount / totalHealing) * mult)) + "%" : "") + "\r\n";
            //bw.write(heal);
            parse.append(heal);
            if (x == 7) {
                x = historyHealers.size();
            }
        }
        parses.setHistoryHealParse(parse);

        this.exportParse(0, true, false, true);
    }//GEN-LAST:event_jMenuItem7ActionPerformed

    private void jMenuItem6ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem6ActionPerformed

        ArrayList historyHealers = new ArrayList();
        ArrayList historyDPSers = new ArrayList();

        ArrayList combatants = this.lastHistoryClicked.getCombatants();

        totalExtendedDPS = 0;
        totalHealing = 0;

        ArrayList tmpHealers = new ArrayList();

        String combatantName;
        DecimalFormat df = new DecimalFormat("###.##");
        int counter = 0;
        for (int x = 0; x < combatants.size(); x++) {
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();

            if (this.lastHistoryClicked.isAlly(combatantName)) {
                double dps = combatant.getExtendedDPS();
                if (dps > 0) {
                    totalExtendedDPS += dps;
                    historyDPSers.add(combatantName + "  |  " + df.format(dps) + "\r\n");
                }

                double healing = combatant.getTotalHealingDone();
                if (healing > 0) {
                    totalHealing += healing;
                    tmpHealers.add(combatantName + "," + healing);
                }
                counter++;
            }
        }

        Collections.sort(historyDPSers, parses);

        ArrayList tmpHealed = new ArrayList();
        for (int x = 0; x < tmpHealers.size(); x++) {
            String tmp = (String) tmpHealers.get(x);
            double tmpHeal = Double.parseDouble(tmp.substring(tmp.indexOf(",") + 1));
            tmpHealed.add(tmpHeal);
        }

        Collections.sort(tmpHealed, Collections.reverseOrder());

        df = new DecimalFormat("#,###,###.##");
        String zonewide = null;
        boolean zwAvailable = false;
        if (this.lastHistoryClicked.toString().equalsIgnoreCase("Zonewide")) {
            zonewide = "Zonewide";
            zwAvailable = true;
        } else {
            zonewide = "Encounter";
        }

        historyDPSers.add(zonewide + " DPS:  (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - {" + df.format(totalExtendedDPS) + "} - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]\r\n");
        historyHealers.add(zonewide + " Healing: (" +
                (!zwAvailable ? this.lastHistoryClicked.getMainEnemy() : this.lastHistoryClicked.getZone()) +
                ") - [" + this.lastHistoryClicked.getEncounterDuration().getDuration() + "]");


        for (int x = 0; x < tmpHealed.size(); x++) {
            double amt = (Double) tmpHealed.get(x);

            String tmpAmt = amt + "";
            for (int y = 0; y < tmpHealers.size(); y++) {
                String temp = (String) tmpHealers.get(y);

                String name = temp.substring(0, temp.indexOf(","));
                if (x < 8) {
                    if (name.length() > _longest) {
                        _longest = name.length();
                    }
                }

                if (temp.contains(tmpAmt)) {
                    historyHealers.add(temp.replaceAll(",", " | "));
                //System.out.println(temp.replaceAll(",", " | "));
                }
            }
        }

        int longest = 0;
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                String name = line.substring(0, line.indexOf("  "));
                if (x < 8) {
                    int length = name.length();
                    if (length > longest) {
                        longest = length;
                    }
                }
            }
        }

        StringBuffer parse = new StringBuffer();
        for (int x = 0; x < historyDPSers.size(); x++) {
            String line = (String) historyDPSers.get(x);
            String name = line.substring(0, line.indexOf("  ")).trim();
            String rest = line.substring(line.indexOf("  ")).trim();

            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                while ((longest - name.length()) > 0) {
                    name += " ";
                }
            }
            String write = this.props.getProperty("dpsParsePrefix") + " " + name + " " + rest + "\r\n";
            //bw.write(write);
            parse.append(write);

            if (x == 7) {
                x = historyDPSers.size();
            }
        }
        //bw.close();
        parses.setHistoryDPSParse(parse);

        parse = new StringBuffer();

        //bw = new BufferedWriter(new FileWriter(healOutput));
        for (int x = 0; x < historyHealers.size(); x++) {
            String line = (String) historyHealers.get(x);
            String name = line.substring(0, line.indexOf(" ")).trim();
            String rest = line.substring(line.indexOf(" "));
            double amount = 0;
            if (!line.contains("Encounter") && !line.contains("Zonewide")) {
                amount = Double.parseDouble(line.substring(line.indexOf("|") + 2));
                //System.out.println(line + ", " + amount + ", " + totalHealing);
                while ((_longest - name.length()) > 0) {
                    name += " ";
                }
            }
            double mult = 100;
            String heal = this.props.getProperty("healParsePrefix") + " " + name + rest +
                    (!line.contains("Encounter") ? " | " + df.format(((amount / totalHealing) * mult)) + "%" : "") + "\r\n";
            //bw.write(heal);
            parse.append(heal);
            if (x == 7) {
                x = historyHealers.size();
            }
        }
        parses.setHistoryHealParse(parse);

        this.exportParse(0, false, false, true);
    }//GEN-LAST:event_jMenuItem6ActionPerformed

    private void jCheckBoxMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxMenuItem3ActionPerformed
        this.reloadAbilityLists();
        if (this.jCheckBoxMenuItem3.isSelected()) {
            this.jCheckBoxMenuItem2.setSelected(false);
            if (!this.arrNever.contains(lastAttackClicked)) {
                this.arrNever.add(lastAttackClicked);
                if (this.arrAlways.contains(lastAttackClicked)) {
                    this.arrAlways.remove(lastAttackClicked);
                }
            }
        } else {
            if (this.arrNever.contains(lastAttackClicked)) {
                this.arrNever.remove(lastAttackClicked);
            }
        }
        this.storeList(this.abilityList);
    }//GEN-LAST:event_jCheckBoxMenuItem3ActionPerformed
    private HashMap abilityList;
    private ArrayList arrAlways;
    private ArrayList arrNever;

    public void reloadAbilityLists() {
        try {
            FileInputStream fis = new FileInputStream("list.dat");
            ObjectInputStream ois = new ObjectInputStream(fis);
            abilityList = (HashMap) ois.readObject();
            arrAlways = (ArrayList) abilityList.get("always");
            arrNever = (ArrayList) abilityList.get("never");

            fis.close();
            ois.close();
        } catch (FileNotFoundException ex) {
            // nothing
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    private void storeList(HashMap map) {
        try {
            FileOutputStream fos = new FileOutputStream("list.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(map);
            fos.close();
            oos.close();
        } catch (FileNotFoundException ex) {
            // nothing
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void jCheckBoxMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxMenuItem2ActionPerformed
        this.reloadAbilityLists();
        if (this.jCheckBoxMenuItem2.isSelected()) {
            this.jCheckBoxMenuItem3.setSelected(false);
            if (!this.arrAlways.contains(lastAttackClicked)) {
                this.arrAlways.add(lastAttackClicked);
                if (this.arrNever.contains(lastAttackClicked)) {
                    this.arrNever.remove(lastAttackClicked);
                }
            }
        } else {
            if (this.arrAlways.contains(lastAttackClicked)) {
                this.arrAlways.remove(lastAttackClicked);
            }
        }
        this.storeList(this.abilityList);
    }//GEN-LAST:event_jCheckBoxMenuItem2ActionPerformed
    String lastAttackClicked;

    private void jCheckBoxMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxMenuItem1ActionPerformed
        //System.out.println("Throwaway is selected = " + jCheckBoxMenuItem1.isSelected());
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();

        if (node == null) {
            return;
        }

        Object nodeData = node.getUserObject();
        if (nodeData instanceof RespawnTimer) {
            RespawnTimer timer = (RespawnTimer) nodeData;
            timer.setThrowaway(!jCheckBoxMenuItem1.isSelected());
            node.setUserObject(timer);
        }
    }//GEN-LAST:event_jCheckBoxMenuItem1ActionPerformed

    private void jMenuItem5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem5ActionPerformed
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();

        if (node == null) {
            return;
        }
        deleteRespawnNode(node);
    }//GEN-LAST:event_jMenuItem5ActionPerformed

    private void deleteRespawnNode(DefaultMutableTreeNode node) {
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree1.getModel();
        RespawnTimer timer = (RespawnTimer) node.getUserObject();
        timer.stopRunning();
        tmpModel.removeNodeFromParent(node);

        try {
            FileInputStream f_in = new FileInputStream("respawns.dat");
            // Read object using ObjectInputStream.
            ObjectInputStream obj_in = new ObjectInputStream(f_in);

            // Read an object.
            Object obj = obj_in.readObject();
            obj_in.close();
            f_in.close();

            HashMap zoneMap = (HashMap) obj;
            HashMap respawns = (HashMap) zoneMap.get(this.currentLocation);
            respawns.remove(timer.getCombatantName());
            zoneMap.put(this.currentLocation, respawns);

            FileOutputStream fos = new FileOutputStream("respawns.dat");
            ObjectOutputStream ois = new ObjectOutputStream(fos);
            ois.writeObject(zoneMap);
            fos.close();
            ois.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void jTree1KeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTree1KeyReleased
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();
        TreePath pathClicked = jTree1.getSelectionPath();
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree1.getModel();

        if (node == null) {
            return;
        }

        Object nodeData = node.getUserObject();
        if (nodeData instanceof RespawnTimer) {
            if (evt.getKeyText(evt.getKeyCode()).equalsIgnoreCase("Delete")) {
                deleteRespawnNode(node);
            }
        }
    }//GEN-LAST:event_jTree1KeyReleased

    private void jTree1MouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTree1MouseReleased
        jTree1.setSelectionPath(jTree1.getPathForLocation(evt.getX(), evt.getY()));
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();

        if (node == null) {
            return;
        }

        if (evt.isPopupTrigger()) {
            Object nodeData = node.getUserObject();

            if (nodeData instanceof RespawnTimer) {
                RespawnTimer timer = (RespawnTimer) nodeData;
                jCheckBoxMenuItem1.setSelected(!timer.isThrowaway());
                jPopupMenu4.show(jTree1, evt.getX(), evt.getY());
            } else {
                jPopupMenu10.show(jTree1, evt.getX(), evt.getY());
            }
        }

    }//GEN-LAST:event_jTree1MouseReleased

    private void formWindowGainedFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowGainedFocus
    }//GEN-LAST:event_formWindowGainedFocus

    private void formWindowLostFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowLostFocus
    }//GEN-LAST:event_formWindowLostFocus

    private void formFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_formFocusLost
    }//GEN-LAST:event_formFocusLost

    private void jMenuItem4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem4ActionPerformed
        if (popupClicked instanceof Encounter && rowClicked > 1) {
            this.exportParse(rowClicked - 2, false, false, false);
        } else if (popupClicked instanceof Encounter && rowClicked == 1) {
            this.exportParse(rowClicked - 2, false, true, false);
        }
    }//GEN-LAST:event_jMenuItem4ActionPerformed

    private Encounter lastHistoryClicked = null;
    private void historyTreeMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_historyTreeMouseReleased
        historyTree.setSelectionPath(historyTree.getPathForLocation(evt.getX(), evt.getY()));
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) historyTree.getLastSelectedPathComponent();
        TreePath pathClicked = historyTree.getSelectionPath();
        DefaultTreeModel tmpModel = (DefaultTreeModel) historyTree.getModel();

        if (node != null) {
            if (evt.isPopupTrigger()) {
                Object nodeData = node.getUserObject();
                if (nodeData instanceof Encounter) {
                    lastHistoryClicked = (Encounter) nodeData;
                    String parseCustom = this.props.getProperty("parseCustom");
                    if (parseCustom == null) {
                        parseCustom = "false";
                    }
                    if (((Encounter) lastHistoryClicked).isZonewide() && Boolean.parseBoolean(parseCustom)) {
                        jPopupMenu8.show(historyTree, evt.getX(), evt.getY());
                    } else {
                        jPopupMenu6.show(historyTree, evt.getX(), evt.getY());
                    }
                } else {
                    jPopupMenu3.show(historyTree, evt.getX(), evt.getY());
                }
            }
        }
    }//GEN-LAST:event_historyTreeMouseReleased

    private void jPopupMenu3MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPopupMenu3MouseClicked
// TODO add your handling code here:
    }//GEN-LAST:event_jPopupMenu3MouseClicked

    private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed
        // TODO add your handling code here:
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) historyTree.getLastSelectedPathComponent();
        TreePath pathClicked = historyTree.getSelectionPath();
        DefaultTreeModel tmpModel = (DefaultTreeModel) historyTree.getModel();

        if (node == null) {
            return;
        }

        Object nodeData = node.getUserObject();
        if (nodeData instanceof String) {
            if (!nodeData.toString().equalsIgnoreCase("History")) {
                if (tmpModel.getChildCount(node) == 0) {
                    //long time = ((DateNode)nodeData).getTime();
                    String _dir = "history" + File.separator + this.getMainCharacter() + "_" + this.getServer() + "_history" + File.separator + nodeData + File.separator;
                    File dir = new File(_dir);

                    File[] zones = dir.listFiles();
                    for (int x = 0; x < zones.length; x++) {
                        ZoneNode zone = new ZoneNode(zones[x].getName(), nodeData.toString());
                        DefaultMutableTreeNode _node = new DefaultMutableTreeNode(zone);
                        node.add(_node);
                    }
                }
                historyTree.expandPath(pathClicked);
            }
        } else if (nodeData instanceof ZoneNode) {
            if (tmpModel.getChildCount(node) == 0) {
                ArrayList encounterNodes = loadZoneNode((ZoneNode) nodeData);
                for (int x = 0; x < encounterNodes.size(); x++) {
                    DefaultMutableTreeNode newNode = (DefaultMutableTreeNode) encounterNodes.get(x);
                    tmpModel.insertNodeInto(newNode, node, 0);
                }
            //tmpModel.reload();
            }
            historyTree.expandPath(pathClicked);
        }
    }//GEN-LAST:event_jMenuItem3ActionPerformed

    private void historyTreeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_historyTreeMouseClicked
        // TODO add your handling code here:
        this.eitherTreeValueChanged(historyTree);
    }//GEN-LAST:event_historyTreeMouseClicked

    private ArrayList loadZoneNode(ZoneNode zn) {
        ArrayList rval = new ArrayList();
        HashMap stored = new HashMap();

        try {
            String history = "history" + File.separator + this.getMainCharacter() + "_" + this.getServer() + "_history"
                    + File.separator + zn.getID() + File.separator + zn + File.separator + "history.dat";
            FileInputStream f_in = new FileInputStream(history);
            // Read object using ObjectInputStream.
            ObjectInputStream obj_in = new ObjectInputStream(f_in);

            // Read an object.
            Object obj = obj_in.readObject();
            stored = (HashMap) obj;

            obj_in.close();
            f_in.close();

            Iterator iter = stored.keySet().iterator();
            while (iter.hasNext()) {
                long id = (Long) iter.next();
                Encounter enc = (Encounter) stored.get(id);

                DefaultMutableTreeNode combatant = null;
                DefaultMutableTreeNode encounter = new DefaultMutableTreeNode(enc);

                ArrayList attacks = null;
                ArrayList combatants = enc.getCombatants();
                ArrayList combatantNodes = new ArrayList();

                for (int x = 0; x < combatants.size(); x++) {
                    Combatant tmp = (Combatant) combatants.get(x);

                    if (!tmp.getName().equalsIgnoreCase("Unknown")) {
                        combatantNodes.add(new CombatantNode(this.calculateEncounterData(tmp, enc.getEncounterDuration()), tmp.getName()));
                    }

                    Collections.sort(combatantNodes, new CombatantNode());

                    for (int i = 0; i < combatantNodes.size(); i++) {
                        CombatantNode cNode = (CombatantNode) combatantNodes.get(i);
                        encounter.add(cNode.getNode());
                    }

                    rval.add(encounter);
                }
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }

        Collections.sort(rval, new Encounter());
        return rval;
    }

    private DefaultMutableTreeNode calculateEncounterData(Combatant tmp, Duration duration) {
        // outgoing nodes
        DefaultMutableTreeNode outgoing = new DefaultMutableTreeNode("Outgoing");
        DefaultMutableTreeNode outgoingMelee = new DefaultMutableTreeNode("Melee");
        DefaultMutableTreeNode outgoingNonMelee = new DefaultMutableTreeNode("Non-Melee");
        DefaultMutableTreeNode outgoingHealing = new DefaultMutableTreeNode("Healing");
        DefaultMutableTreeNode outgoingUnknown = new DefaultMutableTreeNode("Unknown");
        DefaultMutableTreeNode outgoingDamage = new DefaultMutableTreeNode("Total Outgoing Damage");

        // incoming nodes
        DefaultMutableTreeNode incoming = new DefaultMutableTreeNode("Incoming");
        DefaultMutableTreeNode incomingHealing = new DefaultMutableTreeNode("Healing");
        DefaultMutableTreeNode incomingMelee = new DefaultMutableTreeNode("Melee");
        DefaultMutableTreeNode incomingNonMelee = new DefaultMutableTreeNode("Non-Melee");
        DefaultMutableTreeNode incomingUnknown = new DefaultMutableTreeNode("Unknown");
        DefaultMutableTreeNode incomingDamage = new DefaultMutableTreeNode("Total Incoming Damage");

        // self nodes
        DefaultMutableTreeNode self = new DefaultMutableTreeNode("Self");
        DefaultMutableTreeNode selfHealing = new DefaultMutableTreeNode("Healing");
        DefaultMutableTreeNode selfMelee = new DefaultMutableTreeNode("Melee");
        DefaultMutableTreeNode selfNonMelee = new DefaultMutableTreeNode("Non-Melee");
        DefaultMutableTreeNode selfUnknown = new DefaultMutableTreeNode("Unknown");
        DefaultMutableTreeNode selfDamage = new DefaultMutableTreeNode("Total Self Damage");

        AverageNode totalOutgoingNode = new AverageNode(Attack.ATTACK_TYPE_OUTGOING, duration);
        AverageNode totalIncomingNode = new AverageNode(Attack.ATTACK_TYPE_INCOMING, duration);
        AverageNode totalSelfNode = new AverageNode(Attack.ATTACK_TYPE_SELF, duration);

        AverageNode outgoingMeleeNode = new AverageNode(Attack.ATTACK_TYPE_MELEE, duration);
        AverageNode outgoingNonMeleeNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE, duration);
        AverageNode outgoingHealingNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE_HEALING, duration);
        AverageNode outgoingUnknownNode = new AverageNode(Attack.ATTACK_TYPE_UNKNOWN, duration);
        AverageNode incomingMeleeNode = new AverageNode(Attack.ATTACK_TYPE_MELEE, duration);
        AverageNode incomingNonMeleeNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE, duration);
        AverageNode incomingHealingNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE_HEALING, duration);
        AverageNode incomingUnknownNode = new AverageNode(Attack.ATTACK_TYPE_UNKNOWN, duration);
        AverageNode selfMeleeNode = new AverageNode(Attack.ATTACK_TYPE_MELEE, duration);
        AverageNode selfNonMeleeNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE, duration);
        AverageNode selfHealingNode = new AverageNode(Attack.ATTACK_TYPE_NON_MELEE_HEALING, duration);
        AverageNode selfUnknownNode = new AverageNode(Attack.ATTACK_TYPE_UNKNOWN, duration);

        DefaultMutableTreeNode combatant = new DefaultMutableTreeNode(tmp);

        ArrayList attacks = tmp.getOutgoingAttackHashMaps();

        ArrayList healing = new ArrayList();
        ArrayList melee = new ArrayList();
        ArrayList nonMelee = new ArrayList();
        ArrayList unknown = new ArrayList();

        for (int y = 0; y < attacks.size(); y++) {
            AttackHashMap attackMap = (AttackHashMap) attacks.get(y);
            if (attackMap.size() > 0) {
                if (attackMap.isHeal()) { // Attack is a heal
                    healing.add(attackMap);
                } else if (attackMap.isMelee()) { // Attack is Melee
                    melee.add(attackMap);
                } else if (attackMap.isNonMelee()) { // Attack is Non-Melee
                    nonMelee.add(attackMap);
                } else { // Attack is unknown
                    unknown.add(attackMap);
                }
            }
        }
        AttackHashMap compare = new AttackHashMap();
        Collections.sort(healing, compare);
        Collections.sort(melee, compare);
        Collections.sort(nonMelee, compare);
        Collections.sort(unknown, compare);

        for (int i = 0; i < healing.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) healing.get(i);
            outgoingHealingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            outgoingHealing.add(node);
        }
        for (int i = 0; i < melee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) melee.get(i);
            outgoingMeleeNode.addToAttackHashList(attackMap);
            totalOutgoingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            outgoingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            outgoingMelee.add(node);
        }
        for (int i = 0; i < nonMelee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) nonMelee.get(i);
            outgoingNonMeleeNode.addToAttackHashList(attackMap);
            totalOutgoingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            outgoingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            outgoingNonMelee.add(node);
        }

        for (int i = 0; i < unknown.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) unknown.get(i);
            outgoingUnknownNode.addToAttackHashList(attackMap);
            totalOutgoingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            outgoingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            outgoingUnknown.add(node);
        }

        healing = new ArrayList();
        melee = new ArrayList();
        nonMelee = new ArrayList();
        unknown = new ArrayList();

        attacks = tmp.getIncomingAttackHashMaps();
        for (int y = 0; y < attacks.size(); y++) {
            AttackHashMap attackMap = (AttackHashMap) attacks.get(y);
            if (attackMap.size() > 0) {
                if (attackMap.isHeal()) { // Attack is a heal
                    healing.add(attackMap);
                } else if (attackMap.isMelee()) { // Attack is Melee
                    melee.add(attackMap);
                } else if (attackMap.isNonMelee()) { // Attack is Non-Melee
                    nonMelee.add(attackMap);
                } else { // Attack is Unknown
                    unknown.add(attackMap);
                }
            }
        }

        Collections.sort(healing, compare);
        Collections.sort(melee, compare);
        Collections.sort(nonMelee, compare);
        Collections.sort(unknown, compare);

        for (int i = 0; i < healing.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) healing.get(i);
            incomingHealingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            incomingHealing.add(node);
        }
        for (int i = 0; i < melee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) melee.get(i);
            incomingMeleeNode.addToAttackHashList(attackMap);
            totalIncomingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            incomingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            incomingMelee.add(node);
        }
        for (int i = 0; i < nonMelee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) nonMelee.get(i);
            incomingNonMeleeNode.addToAttackHashList(attackMap);
            totalIncomingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            incomingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            incomingNonMelee.add(node);
        }

        for (int i = 0; i < unknown.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) unknown.get(i);
            incomingUnknownNode.addToAttackHashList(attackMap);
            totalIncomingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            incomingDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            incomingUnknown.add(node);
        }

        healing = new ArrayList();
        melee = new ArrayList();
        nonMelee = new ArrayList();
        unknown = new ArrayList();

        attacks = tmp.getSelfAttackHashMaps();
        for (int y = 0; y < attacks.size(); y++) {
            AttackHashMap attackMap = (AttackHashMap) attacks.get(y);
            if (attackMap.size() > 0) {
                if (attackMap.isHeal()) { // Attack is a heal
                    healing.add(attackMap);
                } else if (attackMap.isMelee()) { // Attack is Melee
                    melee.add(attackMap);
                } else if (attackMap.isNonMelee()) { // Attack is Non-Melee
                    nonMelee.add(attackMap);
                } else { // Attack is Unknown
                    unknown.add(attackMap);
                }
            }
        }

        Collections.sort(healing, compare);
        Collections.sort(melee, compare);
        Collections.sort(nonMelee, compare);
        Collections.sort(unknown, compare);

        for (int i = 0; i < healing.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) healing.get(i);
            selfHealingNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            selfHealing.add(node);
        }
        for (int i = 0; i < melee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) melee.get(i);
            selfMeleeNode.addToAttackHashList(attackMap);
            totalSelfNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            selfDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            selfMelee.add(node);
        }
        for (int i = 0; i < nonMelee.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) nonMelee.get(i);
            selfNonMeleeNode.addToAttackHashList(attackMap);
            totalSelfNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            selfDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            selfNonMelee.add(node);
        }

        for (int i = 0; i < unknown.size(); i++) {
            AttackHashMap attackMap = (AttackHashMap) unknown.get(i);
            selfUnknownNode.addToAttackHashList(attackMap);
            totalSelfNode.addToAttackHashList(attackMap);
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(attackMap);
            selfDamage.add(node);
            node = new DefaultMutableTreeNode(attackMap);
            selfUnknown.add(node);
        }

        incomingMelee.setUserObject(incomingMeleeNode);
        incomingNonMelee.setUserObject(incomingNonMeleeNode);
        incomingHealing.setUserObject(incomingHealingNode);
        incomingUnknown.setUserObject(incomingUnknownNode);

        outgoingMelee.setUserObject(outgoingMeleeNode);
        outgoingNonMelee.setUserObject(outgoingNonMeleeNode);
        outgoingHealing.setUserObject(outgoingHealingNode);
        outgoingUnknown.setUserObject(outgoingUnknownNode);
        
        selfMelee.setUserObject(selfMeleeNode);
        selfNonMelee.setUserObject(selfNonMeleeNode);
        selfHealing.setUserObject(selfHealingNode);
        selfUnknown.setUserObject(selfUnknownNode);

        incomingDamage.setUserObject(totalIncomingNode);
        outgoingDamage.setUserObject(totalOutgoingNode);
        selfDamage.setUserObject(totalSelfNode);

        if (outgoingDamage.getChildCount() > 0) {
            outgoing.add(outgoingDamage);
        }

        if (outgoingMelee.getChildCount() > 0) {
            outgoing.add(outgoingMelee);
        }

        if (outgoingNonMelee.getChildCount() > 0) {
            outgoing.add(outgoingNonMelee);
        }

        if (outgoingHealing.getChildCount() > 0) {
            outgoing.add(outgoingHealing);
        }

        if (outgoingUnknown.getChildCount() > 0) {
            outgoing.add(outgoingUnknown);
        }

        if (incomingDamage.getChildCount() > 0) {
            incoming.add(incomingDamage);
        }

        if (incomingMelee.getChildCount() > 0) {
            incoming.add(incomingMelee);
        }

        if (incomingNonMelee.getChildCount() > 0) {
            incoming.add(incomingNonMelee);
        }

        if (incomingHealing.getChildCount() > 0) {
            incoming.add(incomingHealing);
        }

        if (incomingUnknown.getChildCount() > 0) {
            incoming.add(incomingUnknown);
        }

        if (selfDamage.getChildCount() > 0) {
            self.add(selfDamage);
        }

        if (selfMelee.getChildCount() > 0) {
            self.add(selfMelee);
        }

        if (selfNonMelee.getChildCount() > 0) {
            self.add(selfNonMelee);
        }

        if (selfHealing.getChildCount() > 0) {
            self.add(selfHealing);
        }

        if (selfUnknown.getChildCount() > 0) {
            self.add(selfUnknown);
        }

        if (incoming.getChildCount() > 0) {
            combatant.add(incoming);
        }

        if (outgoing.getChildCount() > 0) {
            combatant.add(outgoing);
        }

        if (self.getChildCount() > 0) {
            combatant.add(self);
        }
        return combatant;
    }

    private void formFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_formFocusGained
    }//GEN-LAST:event_formFocusGained

    private void jPopupMenu2MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPopupMenu2MouseClicked
        // TODO add your handling code here:
    }//GEN-LAST:event_jPopupMenu2MouseClicked

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
        if (popupClicked instanceof Encounter && rowClicked > 1) {
            this.exportParse(rowClicked - 2, true, false, false);
        } else if (popupClicked instanceof Encounter && rowClicked == 1) {
            this.exportParse(rowClicked - 2, true, true, false);
        }
    }//GEN-LAST:event_jMenuItem2ActionPerformed

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        // TODO add your handling code here:
        MessageBox mb = new MessageBox();
        Duration timer = null;
        String name = null;
        if (popupClicked instanceof Encounter) {
            name = ((Encounter) popupClicked).getMainEnemy();
        } else if (popupClicked instanceof Combatant) {
            name = ((Combatant) popupClicked).getName();
        }
        String input = null;
        input = mb.doInputBox("Input Respawn Time", "Please input the respawn time for " +
                name + ".\n Enter the time in the format hh:mm or just enter the minutes.",
                "00:00");
        if (input != null) {
            timer = new Duration(input);

            RespawnTimer watcher = new RespawnTimer(name, timer,
                    Boolean.parseBoolean(this.props.getProperty("respawnPopup")), Boolean.parseBoolean(this.props.getProperty("respawnBeep")), this.props.getProperty("doFileCommandsPath"));
//            try {
//                LCTClient client = new LCTClient();
//                client.addRespawnTimer(watcher);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
            watcher.start();
            DefaultMutableTreeNode respawnNode = new DefaultMutableTreeNode(watcher);

            DefaultTreeModel tmpModel = (DefaultTreeModel) jTree1.getModel();
            tmpModel.insertNodeInto(respawnNode, root2, 0);
        }
    //root2.add(respawnNode);
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    public void requestZoneChange(String zone) {
        if (!this.currentLocation.equalsIgnoreCase(zone)) {
            this.combatTail.requestZoneChange(zone);
        }
    }

    public void checkDeadCombatant(String name) {
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree1.getModel();
        int count = tmpModel.getChildCount(root2);
        for (int x = 0; x < count; x++) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tmpModel.getChild(root2, x);
            Object nodeData = node.getUserObject();
            if (nodeData instanceof RespawnTimer) {
                RespawnTimer timer = (RespawnTimer) nodeData;
                if (name.equalsIgnoreCase(timer.getCombatantName())) {
                    //System.out.println("throwaway: " + timer.isThrowaway() + ", remaining: " + timer.getRemainingTime());
                    if (!timer.isThrowaway() || (timer.isThrowaway() && timer.getRemainingTime() <= 0)) {
                        Duration duration = timer.getTotalDuration();
                        timer.stopRunning();
                        RespawnTimer newTimer = new RespawnTimer(name, duration,
                                Boolean.parseBoolean(this.props.getProperty("respawnPopup")), Boolean.parseBoolean(this.props.getProperty("respawnBeep")), this.props.getProperty("doFileCommandsPath"));
                        newTimer.start();
                        newTimer.setThrowaway(timer.isThrowaway());
                        node.setUserObject(newTimer);
                    }
                }
            }
        }
    }

    private void jPopupMenu1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPopupMenu1MouseClicked
        // TODO add your handling code here:
    }//GEN-LAST:event_jPopupMenu1MouseClicked
    private Object popupClicked = null;
    private int rowClicked;
    private Object treeRows = null;

    private void jTreeMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeMouseReleased

        if (evt.isPopupTrigger()) {
            TreePath path = jTree.getPathForLocation(evt.getX(), evt.getY());
            boolean multi = false;
            TreePath[] paths = jTree.getSelectionPaths();
            if (paths != null && paths.length > 1) {
                multi = true;
            }

            if (!multi) {
                jTree.setSelectionPath(path);

                DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
                rowClicked = jTree.getRowForLocation(evt.getX(), evt.getY());
                //(DefaultMutableTreeNode)root.getChildAt(jTree.getClosestRowForLocation(evt.getX(), evt.getY()));

                if (node == null) {
                    return;
                }

                Object nodeData = node.getUserObject();

                if (nodeData instanceof Encounter) {
                    popupClicked = (Encounter) nodeData;
                    String parseCustom = this.props.getProperty("parseCustom");
                    if (parseCustom == null) {
                        parseCustom = "false";
                    }
                    if (((Encounter) popupClicked).isZonewide() && Boolean.parseBoolean(parseCustom)) {
                        jPopupMenu7.show(jTree, evt.getX(), evt.getY());
                    } else {
                        jPopupMenu2.show(jTree, evt.getX(), evt.getY());
                    }
                } else if (nodeData instanceof Combatant) {
                    popupClicked = (Combatant) nodeData;
                    jPopupMenu1.show(jTree, evt.getX(), evt.getY());
                } else if (nodeData instanceof AttackHashMap) {
                    lastAttackClicked = ((AttackHashMap) nodeData).toString();
                    if (this.arrAlways.contains(lastAttackClicked)) {
                        this.jCheckBoxMenuItem2.setSelected(true);
                        this.jCheckBoxMenuItem3.setSelected(false);
                    } else {
                        this.jCheckBoxMenuItem2.setSelected(false);
                    }
                    if (this.arrNever.contains(lastAttackClicked)) {
                        this.jCheckBoxMenuItem3.setSelected(true);
                        this.jCheckBoxMenuItem2.setSelected(false);
                    } else {
                        this.jCheckBoxMenuItem3.setSelected(false);
                    }
                    jPopupMenu5.show(jTree, evt.getX(), evt.getY());
                } else if (nodeData instanceof Duration) {
                    jPopupMenu11.show(jTree, evt.getX(), evt.getY());
                }
            } else {
                //jTree.setSelectionPaths(paths);
                //DefaultTreeModel model = (DefaultTreeModel) jTree.getModel();
                //boolean 
                treeRows = paths;
                this.jPopupMenu9.show(jTree, evt.getX(), evt.getY());
            }
        }
    }//GEN-LAST:event_jTreeMouseReleased

    private void jTabbedPane1MouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTabbedPane1MouseReleased
        
    }//GEN-LAST:event_jTabbedPane1MouseReleased

    private void jMenuMenuSelected(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_jMenuMenuSelected
        // TODO add your handling code here:
        //System.out.println("Menu selected.");
//         else if (evt.getActionCommand().equalsIgnoreCase("EQ2 Running on Same PC")) {
//                    System.out.println("full screen clicked");
//                    if (checkItem.isSelected()) {
//                        if (this.parent.sameComputer) {
//                            this.parent.props.setProperty("eq2OnSamePC", "true");
//                        } else {
//                            this.parent.props.setProperty("eq2OnSamePC", "false");
//                        }
//                        this.parent.saveProperties();
//                    }
//                }
    }//GEN-LAST:event_jMenuMenuSelected

    private void jTreeValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_jTreeValueChanged
        // TODO add your handling code here:
        //this.eitherTreeValueChanged(jTree);
    }//GEN-LAST:event_jTreeValueChanged

    private void eitherTreeValueChanged(JTree tree) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        //System.out.println("LiteGui::jTreeValueChanged()");
        if (node != null) {
            Object nodeData = node.getUserObject();
            if (nodeData instanceof Duration) {
                //this.displayZonewideGraph();
            } else if (nodeData instanceof Encounter) {
                this.updateEncounterTable((Encounter) nodeData);
                this.updateEncounterGraph((Encounter) nodeData);
//                this.sortAllRowsBy((DefaultTableModel) jTable1.getModel(), 3, false);
            } else if (nodeData instanceof Combatant) {
                this.updateCombatantTable((Combatant) nodeData);
            } else if (nodeData instanceof AttackHashMap) {
                this.updateAttackTable((AttackHashMap) nodeData);
            } else if (nodeData instanceof AverageNode) {
                this.updateAttackSummaryTable((AverageNode) nodeData);
            } else if (nodeData instanceof String) {
                if (nodeData.toString().equalsIgnoreCase("incoming")
                    || nodeData.toString().equalsIgnoreCase("outgoing")
                    || nodeData.toString().equalsIgnoreCase("self")) {
                    DefaultMutableTreeNode child = node.getNextNode();
                    this.updateAttackSummaryTable((AverageNode) child.getUserObject());
                }
            } else {
                System.out.println(nodeData.getClass().getName());
            }
        }
    }

    private void updateAttackSummaryTable(AverageNode node) {
        jTable1.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                new String[]{
                    "Attack Name", "Encounter DPS", "Total Amount", "Min Hit", "Max Hit", "Average Hit", "Hit %", "Crit %"
                }) {

            boolean[] canEdit = new boolean[]{
                false, false, false, false, false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit[columnIndex];
            }
        });

        model = (DefaultTableModel) jTable1.getModel();

        ArrayList list = node.getAttackHashMaps();
        DecimalFormat df = new DecimalFormat("#,###,###.##");

        double damage = 0;
        ArrayList types = new ArrayList();

        for (int x = 0; x < list.size(); x++) {
            double crits = 0;
            long maxHit = -1;
            long minHit = 99999999;
            String attackName = null;
            double totalDamage = 0;
            double totalSwings = 0;
            double totalHits = 0;
            
            AttackHashMap map = (AttackHashMap) list.get(x);
            Iterator iter = map.keySet().iterator();

            attackName = map.toString();

            while (iter.hasNext()) {
                ArrayList attackList = (ArrayList) map.get(iter.next());
                for (int y = 0; y < attackList.size(); y++) {
                    Attack attack = (Attack) attackList.get(y);
                    if (attack.isCrit()) {
                        crits++;
                    }
                    if (!attack.isAvoided()) {
                        totalHits++;
                    }
                    totalSwings++;
                    long amount = attack.getAmountOfAttackDamage();
                    if (amount < minHit) {
                        minHit = amount;
                    }

                    if (amount > maxHit) {
                        maxHit = amount;
                    }
                    totalDamage += amount;
                }
            }

            double time = node.getDuration().getDurationInSeconds();
            String[] str = new String[2];
            Vector v = new Vector();
            //"Attack Name", "Encounter DPS", "Total Amount", "Min Hit", "Max Hit", "Average Hit", "Hit %", "Crit %"
            v.add(attackName);
            str[0] = attackName;
            v.add(df.format(totalDamage / time));
            v.add(df.format(totalDamage));
            str[1] = totalDamage + "";
            v.add(df.format(minHit));
            v.add(df.format(maxHit));
            v.add((totalDamage != 0 ? df.format((totalDamage / totalHits)) : "0"));
            v.add((totalDamage != 0 ? df.format((totalHits / totalSwings) * 100) : "0"));
            v.add(df.format(((crits / totalHits) * 100)));
            model.addRow(v);

            damage += totalDamage;
            types.add(str);
        }

        DefaultPieDataset dataset = new DefaultPieDataset();

        ArrayList val = new ArrayList();
        for (int x = 0; x < types.size(); x++) {
            String[] tmp = (String[]) types.get(x);
            tmp[1] = ((Double.parseDouble(tmp[1]) / damage) * 100) + "";
            val.add(0, tmp);
        }
        
        df = new DecimalFormat("###.##");
        Collections.sort(val, new LegendCompare());

        double other = 0;

        for (int x = 0; x < val.size(); x++) {
            String[] tmp = (String[]) val.get(x);
            if (((x < Integer.parseInt(this.props.getProperty("maxPieGraph"))) || (this.arrAlways.contains(tmp[0]))) &&
                    (!this.arrNever.contains(tmp[0]))) {
                dataset.setValue(df.format(Double.parseDouble(tmp[1])) + "% - " + tmp[0], Double.parseDouble(tmp[1]));
            } else {
                other += Double.parseDouble(tmp[1]);
            }
        }

        if (other > 0) {
            dataset.setValue(df.format(other) + "% - Other", other);
        }

        chart = ChartFactory.createPieChart(
                "Damage Types", // chart title
                dataset, // chart data
                true,
                true,
                false);
        PiePlot plot = (PiePlot) chart.getPlot();
        plot.setDirection(Rotation.ANTICLOCKWISE);

        // Specify the colors here
        Color[] colors = {Color.blue, Color.yellow, Color.green, Color.orange, Color.red, Color.black, Color.pink, Color.gray, Color.magenta, Color.cyan};
        PieRenderer renderer = new PieRenderer(colors, false);
        renderer.setColor(plot, dataset);

        BufferedImage image = chart.createBufferedImage(jLabel1.getSize().width, jLabel1.getSize().height);
        jLabel1.setIcon(new ImageIcon(image));

        //"Attack Name", "Encounter DPS", "Total Amount", "Min Hit", "Max Hit", "Average Hit", "Hit %", "Crit %"
        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(jTable1.getModel());
        sorter.setComparator(1, stringToDoubleComparator);
        sorter.setComparator(2, stringToIntComparator);
        sorter.setComparator(3, stringToIntComparator);
        sorter.setComparator(4, stringToIntComparator);
        sorter.setComparator(5, stringToDoubleComparator);
        sorter.setComparator(6, stringToDoubleComparator);
        sorter.setComparator(7, stringToDoubleComparator);
        jTable1.setRowSorter(sorter);
    }

    private static class LegendCompare implements Comparator {

        public LegendCompare() {
        }

        public int compare(Object o1, Object o2) {
            String[] s1 = (String[]) o1;
            String[] s2 = (String[]) o2;
            int rval = 0;

            double percent1 = Double.parseDouble(s1[1]);
            double percent2 = Double.parseDouble(s2[1]);

            if (percent1 > percent2) {
                rval = -1;
            } else if (percent1 < percent2) {
                rval = 1;
            } else {
                rval = 0;
            }

            return rval;
        }
    }

    /*
     * A simple renderer for setting custom colors
     * for a pie chart.
     */
    public static class PieRenderer {

        private Color[] color;
        private boolean swiped;

        public PieRenderer(Color[] color, boolean swiped) {
            this.color = color;
            this.swiped = swiped;
        }

        public void setColor(PiePlot plot, DefaultPieDataset dataset) {
            List<Comparable> keys = dataset.getKeys();
            int aInt;

            if (!this.swiped) {
                for (int i = 0; i < keys.size(); i++) {
                    aInt = i % this.color.length;
                    plot.setSectionPaint(keys.get(i), this.color[aInt]);
                }
            } else {
                GradientPaint gp1 = new GradientPaint(0.0f, 0.0f, Color.green,
                        0.0f, 0.0f, new Color(0, 64, 0));
                for (int i = 0; i < keys.size(); i++) {
                    aInt = i % this.color.length;
                    if (i == 0) {
                        plot.setSectionPaint(keys.get(i), gp1);
                    } else {
                        plot.setSectionPaint(keys.get(i), this.color[aInt]);
                    }
                }
            }
        }
    }

    private void updateAttackTable(AttackHashMap a) {
        String[] columnTitles = new String[6];
        columnTitles[0] = "Timestamp";
        if (a.getDirection() == Attack.ATTACK_TYPE_INCOMING) {
            columnTitles[1] = "Attacker";
        } else {
            columnTitles[1] = "Target";
        }
        columnTitles[2] = "Amount";
        columnTitles[3] = "Critical Hit";
        columnTitles[4] = "Type";
        columnTitles[5] = "Avoid Type";
        jTable1.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                columnTitles) {

            boolean[] canEdit = new boolean[]{
                false, false, false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit[columnIndex];
            }
        });
        model = (DefaultTableModel) jTable1.getModel();
        //jTable1.revalidate();

        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss a");

        Vector v = new Vector();
        ArrayList attacks = (ArrayList) a.get(a.toString());
        for (int x = 0; x < attacks.size(); x++) {
            v = new Vector();
            Attack attack = (Attack) attacks.get(x);
            v.add(sdf.format(new Date(attack.getTimeStamp())));
            if (a.getDirection() == Attack.ATTACK_TYPE_INCOMING) {
                v.add(attack.getAttacker());
            } else {
                v.add(attack.getTarget());
            }
            v.add(attack.getAmountOfAttackDamage());
            v.add(attack.isCrit());
            v.add(attack.getAttackType());
            if (attack.isAvoided()) {
                v.add(attack.getReasonAvoidedString());
            }
            model.addRow(v);
        }

        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(jTable1.getModel());
        sorter.setComparator(2, intComparator);
        jTable1.setRowSorter(sorter);
    }

    private void updateCombatantTable(Combatant c) {
        jTable1.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                new String[]{
                    "Damage Type", "Amount", "Min Hit", "Max Hit", "Hits", "Crits", "Swings", "Hit %"
                }) {

            boolean[] canEdit = new boolean[]{
                false, false, false, false, false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit[columnIndex];
            }
        });

        model = (DefaultTableModel) jTable1.getModel();

//        model.addColumn("Damage Type");
//        model.addColumn("Amount");
//        model.addColumn("Min Hit");
//        //model.addColumn("Average Hit");
//        model.addColumn("Max Hit");
//        model.addColumn("Hits");
//        model.addColumn("Crits");
//        model.addColumn("Swings");
//        model.addColumn("Hit %");

        DecimalFormat df = new DecimalFormat("#,###,###.##");

        double meleeHits = c.getTotalOutgoingMeleeHits();
        double meleeSwings = c.getTotalOutgoingMeleeSwings();

//        double unknownHits = c.getTotalOutgoingUnknownHits();
//        double unknownSwings = c.getTotalOutgoingUnknownSwings();

        long meleeDamageDealt = c.getMeleeDamageDealt();
        long nonMeleeDamageDealt = c.getNonMeleeDamageDealt();
//        long unknownDamageDealt = c.getUnknownDamageDealt();

        long outgoingMeleeMinHit = c.getOutgoingMeleeMinHit();
        outgoingMeleeMinHit = (outgoingMeleeMinHit == 99999999 ? 0 : outgoingMeleeMinHit);

        long outgoingNonMeleeMinHit = c.getOutgoingNonMeleeMinHit();
        outgoingNonMeleeMinHit = (outgoingNonMeleeMinHit == 99999999 ? 0 : outgoingNonMeleeMinHit);

//        long outgoingUnknownMinHit = c.getOutgoingUnknownMinHit();
//        outgoingUnknownMinHit = (outgoingUnknownMinHit == 99999999 ? 0 : outgoingUnknownMinHit);

        long outgoingMeleeMaxHit = c.getOutgoingMeleeMaxHit();
        long outgoingNonMeleeMaxHit = c.getOutgoingNonMeleeMaxHit();
//        long outgoingUnknownMaxHit = c.getOutgoingUnknownMaxHit();

        long outgoingMeleeCrits = c.getTotalOutgoingMeleeCrits();
        long outgoingNonMeleeCrits = c.getTotalOutgoingNonMeleeCrits();
//        long outgoingUnknownCrits = c.getTotalOutgoingUnknownCrits();

        Vector v = new Vector();
        v.add("Outgoing Melee");
        v.add(df.format(meleeDamageDealt));
        v.add(df.format(outgoingMeleeMinHit));
        v.add(df.format(outgoingMeleeMaxHit));
        v.add(df.format(meleeHits));
        v.add(df.format(outgoingMeleeCrits));
        v.add(df.format(meleeSwings));
        v.add((meleeSwings > 0 ? df.format((meleeHits / meleeSwings) * 100) : "NaN"));
        model.addRow(v);

        double nonMeleeHits = c.getTotalOutgoingNonMeleeHits();
        double nonMeleeSwings = c.getTotalOutgoingNonMeleeSwings();

        v = new Vector();
        v.add("Outgoing Non-Melee");
        v.add(df.format(nonMeleeDamageDealt));
        v.add(df.format(outgoingNonMeleeMinHit));
        v.add(df.format(outgoingNonMeleeMaxHit));
        v.add(df.format(nonMeleeHits));
        v.add(df.format(outgoingNonMeleeCrits));
        v.add(df.format(nonMeleeSwings));
        v.add((nonMeleeSwings > 0 ? df.format((nonMeleeHits / nonMeleeSwings) * 100) : "NaN"));
        model.addRow(v);

//        v = new Vector();
//        v.add("Outgoing Unknown");
//        v.add(df.format(unknownDamageDealt));
//        v.add(df.format(outgoingUnknownMinHit));
//        v.add(df.format(outgoingUnknownMaxHit));
//        v.add(df.format(unknownHits));
//        v.add(df.format(outgoingUnknownCrits));
//        v.add(df.format(unknownSwings));
//        v.add((unknownSwings > 0 ? df.format((unknownHits / unknownSwings) * 100) : "NaN"));
        //model.addRow(v);

        v = new Vector();
        v.add("Outgoing Total");
        v.add(df.format(meleeDamageDealt + nonMeleeDamageDealt));
        v.add(df.format((outgoingMeleeMinHit < outgoingNonMeleeMinHit ? outgoingMeleeMinHit : outgoingNonMeleeMinHit)));
        v.add(df.format((outgoingMeleeMaxHit < outgoingNonMeleeMaxHit ? outgoingMeleeMaxHit : outgoingNonMeleeMaxHit)));
        v.add(df.format(meleeHits + nonMeleeHits));
        v.add(df.format(outgoingMeleeCrits + outgoingNonMeleeCrits));
        v.add(df.format(meleeSwings + nonMeleeSwings));
        v.add(((meleeSwings + nonMeleeSwings) > 0 ? df.format(((meleeHits + nonMeleeHits) / (meleeSwings + nonMeleeSwings)) * 100) : "NaN"));
        model.addRow(v);

        double incomingMeleeHits = c.getTotalIncomingMeleeHits();
        double incomingMeleeSwings = c.getTotalIncomingMeleeSwings();

//        double incomingUnknownHits = c.getTotalIncomingUnknownHits();
//        double incomingUnknownSwings = c.getTotalIncomingUnknownSwings();

        long meleeDamageTaken = c.getMeleeDamageTaken();
        long nonMeleeDamageTaken = c.getNonMeleeDamageTaken();
//        long unknownDamageTaken = c.getUnknownDamageTaken();

        long incomingMeleeMinHit = c.getIncomingMeleeMinHit();
        incomingMeleeMinHit = (incomingMeleeMinHit == 99999999 ? 0 : incomingMeleeMinHit);

        long incomingNonMeleeMinHit = c.getIncomingNonMeleeMinHit();
        incomingNonMeleeMinHit = (incomingNonMeleeMinHit == 99999999 ? 0 : incomingNonMeleeMinHit);

//        long incomingUnknownMinHit = c.getIncomingUnknownMinHit();
//        incomingUnknownMinHit = (incomingUnknownMinHit == 99999999 ? 0 : incomingUnknownMinHit);

        long incomingMeleeMaxHit = c.getIncomingMeleeMaxHit();
        long incomingNonMeleeMaxHit = c.getIncomingNonMeleeMaxHit();
//        long incomingUnknownMaxHit = c.getIncomingUnknownMaxHit();

        long incomingMeleeCrits = c.getTotalIncomingMeleeCrits();
        long incomingNonMeleeCrits = c.getTotalIncomingNonMeleeCrits();
//        long incomingUnknownCrits = c.getTotalIncomingUnknownCrits();

        v = new Vector();
        v.add("Incoming Melee");
        v.add(df.format(meleeDamageTaken));
        v.add(df.format(incomingMeleeMinHit));
        v.add(df.format(incomingMeleeMaxHit));
        v.add(df.format(incomingMeleeHits));
        v.add(df.format(incomingMeleeCrits));
        v.add(df.format(incomingMeleeSwings));
        v.add((incomingMeleeSwings > 0 ? df.format((incomingMeleeHits / incomingMeleeSwings) * 100) : "NaN"));
        model.addRow(v);

        double incomingNonMeleeHits = c.getTotalIncomingNonMeleeHits();
        double incomingNonMeleeSwings = c.getTotalIncomingNonMeleeSwings();

        v = new Vector();
        v.add("Incoming Non-Melee");
        v.add(df.format(nonMeleeDamageTaken));
        v.add(df.format(incomingNonMeleeMinHit));
        v.add(df.format(incomingNonMeleeMaxHit));
        v.add(df.format(incomingNonMeleeHits));
        v.add(df.format(incomingNonMeleeCrits));
        v.add(df.format(incomingNonMeleeSwings));
        v.add((incomingNonMeleeSwings > 0 ? df.format((incomingNonMeleeHits / incomingNonMeleeSwings) * 100) : "NaN"));
        model.addRow(v);

//        v = new Vector();
//        v.add("Incoming Unknown");
//        v.add(df.format(unknownDamageTaken));
//        v.add(df.format(incomingUnknownMinHit));
//        v.add(df.format(incomingUnknownMaxHit));
//        v.add(df.format(incomingUnknownHits));
//        v.add(df.format(incomingUnknownCrits));
//        v.add(df.format(incomingUnknownSwings));
//        v.add((incomingUnknownSwings > 0 ? df.format((incomingUnknownHits / incomingUnknownSwings) * 100) : "NaN"));
        //model.addRow(v);

        v = new Vector();
        v.add("Incoming Total");
        v.add(df.format(meleeDamageTaken + nonMeleeDamageTaken));
        v.add(df.format((incomingMeleeMinHit < incomingNonMeleeMinHit ? incomingMeleeMinHit : incomingNonMeleeMinHit)));
        v.add(df.format((incomingMeleeMaxHit < incomingNonMeleeMaxHit ? incomingMeleeMaxHit : incomingNonMeleeMaxHit)));
        v.add(df.format(incomingMeleeHits + incomingNonMeleeHits));
        v.add(df.format(incomingMeleeCrits + incomingNonMeleeCrits));
        v.add(df.format(incomingMeleeSwings + incomingNonMeleeSwings));
        v.add(((incomingMeleeSwings + incomingNonMeleeSwings) > 0 ? df.format(((incomingNonMeleeHits + incomingMeleeHits) / (incomingMeleeSwings + incomingNonMeleeSwings)) * 100) : "NaN"));
        model.addRow(v);

        //"Damage Type", "Amount", "Min Hit", "Max Hit", "Hits", "Crits", "Swings", "Hit %"
        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(jTable1.getModel());
        sorter.setComparator(1, stringToIntComparator);
        sorter.setComparator(2, stringToIntComparator);
        sorter.setComparator(3, stringToIntComparator);
        sorter.setComparator(4, stringToIntComparator);
        sorter.setComparator(5, stringToIntComparator);
        sorter.setComparator(6, stringToIntComparator);
        sorter.setComparator(7, stringToDoubleComparator);
        jTable1.setRowSorter(sorter);
    }

    private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTable1MouseClicked
        //System.out.println(jTable1.get)

        int column = jTable1.getSelectedColumn();
        if (jTable1.isColumnSelected(1) || jTable1.isColumnSelected(3) || jTable1.isColumnSelected(5)) {
//            this.sortAllRowsBy((DefaultTableModel) jTable1.getModel(), column, false);
        }
    }//GEN-LAST:event_jTable1MouseClicked

    public void sortAllRowsBy(DefaultTableModel model, int colIndex, boolean ascending) {
        Vector data = model.getDataVector();
        Collections.sort(data, new ColumnSorter(colIndex, ascending));
        model.fireTableStructureChanged();
    }

    // This comparator is used to sort vectors of data
    public class ColumnSorter implements Comparator {

        int colIndex;
        boolean ascending;

        ColumnSorter(int colIndex, boolean ascending) {
            this.colIndex = colIndex;
            this.ascending = ascending;
        }

        public int compare(Object a, Object b) {
            Vector v1 = (Vector) a;
            Vector v2 = (Vector) b;
            Object o1 = v1.get(colIndex);
            Object o2 = v2.get(colIndex);

            // Treat empty strains like nulls
            if (o1 instanceof String && ((String) o1).length() == 0) {
                o1 = null;
            }
            if (o2 instanceof String && ((String) o2).length() == 0) {
                o2 = null;
            }

            // Sort nulls so they appear last, regardless
            // of sort order
            if (o1 == null && o2 == null) {
                return 0;
            } else if (o1 == null) {
                return 1;
            } else if (o2 == null) {
                return -1;
            } else if (o1 instanceof Comparable) {
                if (ascending) {
                    return ((Comparable) o1).compareTo(o2);
                } else {
                    return ((Comparable) o2).compareTo(o1);
                }
            } else {
                if (ascending) {
                    return o1.toString().compareToIgnoreCase(o2.toString());
                } else {
                    return o2.toString().compareToIgnoreCase(o1.toString());
                }
            }
        }
    };
    private TreeRefresh treeRefresh = null;

    private void jTabbedPane1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTabbedPane1MouseClicked
        // TODO add your handling code here:
        if ((jTabbedPane1.getSelectedIndex() == 1)) {
            //treeRefresh = new TreeRefresh(this);
            //treeRefresh.start();
            jTree1.expandRow(0);
        } else if (jTabbedPane1.getSelectedIndex() == 2) {
            this.populateHistoryTab();
        } else if (jTabbedPane1.getSelectedIndex() != 1) {
            if (treeRefresh != null) {
                treeRefresh.stopRunning();
            }
        }
    }//GEN-LAST:event_jTabbedPane1MouseClicked

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing

        if (this.parseWindow != null && this.parseWindow.isVisible()) {
            this.parseWindow.dispose();
        }

        if (this.timer != null && this.timer.isVisible()) {
            this.timer.dispose();
        }
        //this.setVisible(false);
        this.dispose();
        if (this.combatTail != null) {
            this.combatTail.stopRunning();
        }
//        if (this.systemTail != null) {
//            this.systemTail.stopRunning();
//        }
        if (this.commThread != null) {
            //this.sendData("::removeid::" + this.characterID);
            this.sendData(new Line("", Line.DISCONNECT));
            this.commThread.closeSocket();
        }
        //this.storeRespawnTimers();
        this.storeEncounterHistory();

        switch (Integer.parseInt(this.props.getProperty("currentFile"))) {
            case 1:
                try {
                    copy(new File("LCT1.jar"), new File("LCT.jar"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                break;
            default:
                break;
        }

        File file = new File(this.combatLogFileLocation);
        if (!this.combatLogFileLocation.equalsIgnoreCase("<setup>")) {
            String archivePath = this.combatLogFileLocation.substring(0, this.combatLogFileLocation.lastIndexOf(File.separator))
                    + File.separator + "archive" + File.separator + "combat.log_" + System.currentTimeMillis();
            boolean success = file.renameTo(new File(archivePath));
            if (success) {
                file = new File(this.combatLogFileLocation);
                if (!file.exists()) {
                    try {
                        file.createNewFile();
                    } catch (IOException ex) {
                        Logger.getLogger(LiteGui.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
        this.props.setProperty("guiX", this.getX() + "");
        this.props.setProperty("guiY", this.getY() + "");
        this.props.setProperty("guiWidth", this.getWidth() + "");
        this.props.setProperty("guiHeight", this.getHeight() + "");
        this.saveProperties();
    }//GEN-LAST:event_formWindowClosing

    private void jTabbedPane1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTabbedPane1KeyPressed
        // TODO add your handling code here:
    }//GEN-LAST:event_jTabbedPane1KeyPressed

    private void jTreeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeMouseClicked
        // TODO add your handling code here:
        this.eitherTreeValueChanged(jTree);
    }//GEN-LAST:event_jTreeMouseClicked

    private void storeRespawnTimers() {
        String zone = this.currentLocation;
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree1.getModel();
        int count = tmpModel.getChildCount(root2);

        if (count > 0) {
            //System.out.println("Storing respawn timers for " + zone);
            try {
                HashMap list = null;
                HashMap map = null;
                File respawnFile = new File("respawns.dat");
                if (respawnFile.exists()) {
                    FileInputStream fis = new FileInputStream(respawnFile);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    map = (HashMap) ois.readObject();
                    list = (HashMap) map.get(zone);
                    fis.close();
                    ois.close();
                } else {
                    map = new HashMap();
                    list = new HashMap();
                }

                if (list == null) {
                    list = new HashMap();
                }

                for (int x = 0; x < count; x++) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) tmpModel.getChild(root2, x);
                    RespawnTimer timer = (RespawnTimer) node.getUserObject();
                    String name = timer.getCombatantName();
                    timer.reset();
                    //if (!list.containsKey(name)) {
                    list.put(name, node);
                //}
                }
                //Collections.sort(list, new RespawnTimer());
                map.put(zone, list);

                FileOutputStream fos = new FileOutputStream(new File("respawns.dat"));
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                oos.writeObject(map);
                fos.close();
                oos.close();
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }

            root2 = new DefaultMutableTreeNode("Respawn Timers");
            jTree1.setModel(new DefaultTreeModel(root2));
//            for (int x = 0; x < count; x++) {
        //jTree1.collapseRow(x);
//                tmpModel.removeNodeFromParent((MutableTreeNode) tmpModel.getChild(root2, 0));
//            }

        }
    }

    private void updateEncounterTable(Encounter encounter) {
        jTable1.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                new String[]{
                    "Combatant Name", "Allied Status", "Duration", "Encounter DPS", "Damage Dealt", "Amount Healed", "Damage Taken"
                }) {

            boolean[] canEdit = new boolean[]{
                false, false, false, false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit[columnIndex];
            }
        });

        model = (DefaultTableModel) jTable1.getModel();

        while (model.getRowCount() > 0) {
            model.removeRow(0);
        }

        //jTable1.revalidate();
        ArrayList combatants = encounter.getCombatants();
        int combatantCount = combatants.size();
        String combatantName = null;

        DecimalFormat df = new DecimalFormat("###.##");

        for (int x = 0; x < combatantCount; x++) {
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();
            if (!combatantName.equalsIgnoreCase("Unknown")) {
                Vector v = new Vector();
                //"Combatant Name", "Allied Status", "Duration", "Extended DPS", "Damage Dealt", "Amount Healed", "Damage Taken"
                v.add(combatantName);
                v.add((encounter.isAlly(combatantName) ? "Friend" : "Enemy"));
                v.add(combatant.getDuration().getDuration());
                v.add(Double.parseDouble(df.format(combatant.getExtendedDPS())));
                v.add(combatant.getTotalDamageDealt());
                v.add(combatant.getTotalHealingDone());
                v.add(combatant.getDamageTaken());

                model.addRow(v);
            }
        }

        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(jTable1.getModel());
        sorter.setComparator(2, durationComparator);
        sorter.setComparator(3, doubleComparator);
        sorter.setComparator(4, intComparator);
        sorter.setComparator(5, intComparator);
        sorter.setComparator(6, intComparator);
        jTable1.setRowSorter(sorter);
        
//        List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
//        sortKeys.add(new RowSorter.SortKey(3, SortOrder.DESCENDING));
//        sorter.setSortKeys(sortKeys);
    }

    private void formComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentResized
        jLabel1.setSize(layeredPane.getWidth(), layeredPane.getHeight());
        if (this.chart != null) {
            BufferedImage image = chart.createBufferedImage(jLabel1.getSize().width, jLabel1.getSize().height);
            jLabel1.setIcon(new ImageIcon(image));
            if (!this.sameComputer) {
                //this.repaint();
            }
        }
    }//GEN-LAST:event_formComponentResized

    /**
     * A custom renderer that returns a different color for each item in a single series.
     */
    class CustomRenderer extends BarRenderer {

        /** The colors. */
        private GradientPaint[] colors;
        private int mainCharacterIndex = 0;

        /**
         * Creates a new renderer.
         *
         * @param colors  the colors.
         */
        public CustomRenderer(final GradientPaint[] colors, int mainCharacterIndex) {
            //System.out.println("CustomRenderer::() - Passed mainCharacterIndex = " + mainCharacterIndex + ", this.mainCharacterIndex = " + this.mainCharacterIndex);
            this.colors = colors;
            this.mainCharacterIndex = mainCharacterIndex;
        }

        /**
         * Returns the paint for an item.  Overrides the default behaviour inherited from
         * AbstractSeriesRenderer.
         *
         * @param row  the series.
         * @param column  the category.
         *
         * @return The item color.
         */
        public Paint getItemPaint(final int row, final int column) {
            GradientPaint gp1 = new GradientPaint(0.0f, 0.0f, Color.green,
                    0.0f, 0.0f, new Color(0, 64, 0));
            GradientPaint gp2 = new GradientPaint(0.0f, 0.0f, Color.yellow,
                    0.0f, 0.0f, new Color(0, 64, 0));
            Paint rval = null;
            if ((this.mainCharacterIndex != -1) && (column == this.mainCharacterIndex)) {
                //System.out.println("CustomRenderer::getItemPaint() - column = " + column + ", this.mainCharacterIndex = " + this.mainCharacterIndex);
                if (row == 0) {
                    rval = gp1;
                } else {
                    rval = gp2;
                }
            } else {
                GradientPaint gp3 = new GradientPaint(0.0f, 0.0f, Color.cyan,
                        0.0f, 0.0f, new Color(0, 0, 64));
                GradientPaint gp4 = new GradientPaint(0.0f, 0.0f, Color.magenta,
                        0.0f, 0.0f, new Color(64, 0, 0));
                GradientPaint[] arr = {gp3, gp4};

                if (row == 0) {
                    rval = this.colors[column % this.colors.length];
                } else {
                    rval = arr[column % arr.length];
                }
            }
            return rval;
        }
    }

    private void clearEncounters() {
//        DefaultTreeModel tmpModel = (DefaultTreeModel)jTree.getModel();
//        for (int x = 0; x < tmpModel.getChildCount(root); x++) {
//            tmpModel.removeNodeFromParent((DefaultMutableTreeNode)tmpModel.getChild(root, x));
//        }
        root = new DefaultMutableTreeNode(new Duration());
        zonewide = new DefaultMutableTreeNode("Zonewide");
        jTree.setModel(new DefaultTreeModel(root));
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree.getModel();
        tmpModel.insertNodeInto(zonewide, root, 0);
    }

    public void displayZonewideGraph() {
        Iterator iter = this.zonewideDPS.keySet().iterator();
        int x = 0;
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        ArrayList tmpZonewideCombatants = new ArrayList();

        // row keys...
        String series = "First";

        // create the dataset...

        int mainCharacterIndex = -1;

        while (iter.hasNext()) {
            String combatantName = (String) iter.next();
            //System.out.println("Zonewide combatant name = " + combatantName);
            Combatant tmpZonewideCombatant = new Combatant();
            tmpZonewideCombatant.setName(combatantName);
            int zonewide = (Integer) this.zonewideDPS.get(combatantName);
            tmpZonewideCombatant.setTotalDamageDealtForZonewide(zonewide, (Duration) root.getUserObject());
            tmpZonewideCombatants.add(tmpZonewideCombatant);
        }

        Collections.sort(tmpZonewideCombatants, new Combatant());

        int counter = 0;
        for (int y = 0; y < tmpZonewideCombatants.size(); y++) {
            Combatant tmp = (Combatant) tmpZonewideCombatants.get(y);
            String combatantName = tmp.getName();

            if (this.zonewideEncounter.isAlly(combatantName)) {
                counter++;
                double tmpDPS = tmp.getExtDPS((Duration) root.getUserObject());
                if (combatantName.equalsIgnoreCase(this.getMainCharacter())) {
                    mainCharacterIndex = counter;
                }
                if (tmpDPS > 0) {
                    dataset.addValue(tmpDPS, series, combatantName);
                }
            }
        }

        // create the chart...
        chart = ChartFactory.createBarChart(
                "Zonewide - [" + ((Duration) root.getUserObject()).getDuration() + "]", // chart title
                "Allies", // domain axis label
                "Encounter DPS", // range axis label
                dataset, // data
                PlotOrientation.VERTICAL, // orientation
                false, // include legend
                true, // tooltips?
                false // URLs?
                );

        // set the background color for the chart...
        chart.setBackgroundPaint(Color.white);

        // get a reference to the plot for further customization...
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setDomainGridlinePaint(Color.white);
        plot.setDomainGridlinesVisible(true);
        plot.setRangeGridlinePaint(Color.white);

        // set the range axis to display integers only...
        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        GradientPaint gp0 = new GradientPaint(0.0f, 0.0f, Color.blue,
                0.0f, 0.0f, new Color(0, 0, 64));
        GradientPaint gp1 = new GradientPaint(0.0f, 0.0f, Color.red,
                0.0f, 0.0f, new Color(64, 0, 0));

        GradientPaint[] arr = {gp0, gp1};

        // disable bar outlines...
        final BarRenderer renderer = new CustomRenderer(arr, mainCharacterIndex);

        DecimalFormat df = new DecimalFormat("##,###");
        renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", df));
        renderer.setItemLabelsVisible(true);

        plot.setRenderer(renderer);

        renderer.setDrawBarOutline(true);

        CategoryAxis domainAxis = plot.getDomainAxis();

        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        //CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));

        BufferedImage image = chart.createBufferedImage(jLabel1.getSize().width, jLabel1.getSize().height);
        jLabel1.setIcon(new ImageIcon(image));
    }
    int _longest = 0;
    double totalHealing = 0;
    double totalExtendedDPS = 0;

    public void updateEncounterGraph(Encounter encounter) {
        // row keys...
        String series = "First";

        // create the dataset...
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        ArrayList combatants = encounter.getCombatants();

        boolean displayDPS = Boolean.parseBoolean(this.props.getProperty("displayDPS"));
        boolean displayHPS = Boolean.parseBoolean(this.props.getProperty("displayHPS"));

        String title = "Total";
        boolean both = false;

        if (displayDPS == true) {
            title += " DPS";
            if (displayHPS == true) {
                //title += " / HPS";
                both = true;
            }
        } else if (displayHPS == true) {
            title += " HPS";
        }

        if (!both) {
            if (displayHPS) {
                Collections.sort(combatants, new HealSort());
            } else if (displayDPS) {
                Collections.sort(combatants, new Combatant());
            }
        } else {
            Collections.sort(combatants, new Combatant());
        }

        String combatantName = null;

        int mainCharacterIndex = -1;
        int countOffset = 0;

        DecimalFormat df = new DecimalFormat("#,###,###.##");

        healers = new ArrayList();
        dpsers = new ArrayList();

        dpsers.add("Encounter DPS:  (" + encounter.getMainEnemy() +
                ") - {" + df.format(totalExtendedDPS) + "} - [" + encounter.getEncounterDuration().getDuration() + "]\r\n");
        healers.add("Encounter Healing: (" + encounter.getMainEnemy() +
                ") - [" + encounter.getEncounterDuration().getDuration() + "]");

        totalExtendedDPS = 0;
        totalHealing = 0;

        ArrayList tmpHealers = new ArrayList();
        df = new DecimalFormat("###.##");

        int counter = 0;
        for (int x = 0; x < combatants.size(); x++) {
            countOffset++;
            Combatant combatant = (Combatant) combatants.get(x);
            combatantName = combatant.getName();

            if (encounter.isAlly(combatantName)) {
                if (combatantName.equalsIgnoreCase(this.getMainCharacter())) {
                    mainCharacterIndex = counter;
                }
                double dps = combatant.getExtendedDPS();
                if (dps > 0) {
                    totalExtendedDPS += dps;
                    dpsers.add(combatantName + "  |  " + df.format(dps) + "\r\n");
                    if (displayDPS) {
                        dataset.addValue(dps, series, combatantName);
                    }
                }

                double healing = combatant.getTotalHealingDone();
                if (healing > 0) {
                    totalHealing += healing;
                    tmpHealers.add(combatantName + "," + healing);
                    if (displayHPS) {
                        double healingPerSecond = healing / encounter.getEncounterDuration().getDurationInSeconds();
                        if (healingPerSecond > 1) {
                            dataset.addValue(healingPerSecond, (both ? "new" : series), combatantName);
                        }
                    }
                }
                counter++;
            } else {
                countOffset--;
            }
        }

        ArrayList tmpHealed = new ArrayList();
        for (int x = 0; x < tmpHealers.size(); x++) {
            String tmp = (String) tmpHealers.get(x);
            double tmpHeal = Double.parseDouble(tmp.substring(tmp.indexOf(",") + 1));
            tmpHealed.add(tmpHeal);
        }

        Collections.sort(tmpHealed, Collections.reverseOrder());

        for (int x = 0; x < tmpHealed.size(); x++) {
            double amt = (Double) tmpHealed.get(x);

            String tmpAmt = amt + "";
            for (int y = 0; y < tmpHealers.size(); y++) {
                String temp = (String) tmpHealers.get(y);

                String name = temp.substring(0, temp.indexOf(","));
                if (x < 8) {
                    if (name.length() > _longest) {
                        _longest = name.length();
                    }
                }

                if (temp.contains(tmpAmt)) {
                    healers.add(temp.replaceAll(",", " | "));
                //System.out.println(temp.replaceAll(",", " | "));
                }
            }
        }

        df = new DecimalFormat("#,###,###.##");
        // create the chart...

        double totalHealingPerSecond = (totalHealing / encounter.getEncounterDuration().getDurationInSeconds());

        chart = ChartFactory.createBarChart(
                "Encounter - [" + encounter.getEncounterDuration().getDuration() + "] - " + title + ": " +
                (displayDPS ? df.format(totalExtendedDPS) : "") + (displayHPS ? (both ? ", Total HPS:" : "") + df.format(totalHealingPerSecond) : ""),
                "Allies", // domain axis label
                title, // range axis label
                dataset, // data
                PlotOrientation.VERTICAL, // orientation
                false, // include legend
                true, // tooltips?
                false // URLs?
                );

        // set the background color for the chart...
        chart.setBackgroundPaint(Color.white);

        // get a reference to the plot for further customization...
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setDomainGridlinePaint(Color.white);
        plot.setDomainGridlinesVisible(true);
        plot.setRangeGridlinePaint(Color.white);

        // set the range axis to display integers only...
        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        GradientPaint gp0 = new GradientPaint(0.0f, 0.0f, Color.blue,
                0.0f, 0.0f, new Color(0, 0, 64));
        GradientPaint gp1 = new GradientPaint(0.0f, 0.0f, Color.red,
                0.0f, 0.0f, new Color(64, 0, 0));
        GradientPaint gp3 = new GradientPaint(0.0f, 0.0f, Color.cyan,
                0.0f, 0.0f, new Color(0, 0, 64));
        GradientPaint gp4 = new GradientPaint(0.0f, 0.0f, Color.magenta,
                0.0f, 0.0f, new Color(64, 0, 0));

        GradientPaint[] arr1 = {gp0, gp1};
        GradientPaint[] arr2 = {gp3, gp4};

        Font font = new Font(this.props.getProperty("fontName"), Font.PLAIN, Integer.parseInt(this.props.getProperty("fontSize")));

        BarRenderer renderer = null;

        if (!both) {
            if (displayHPS) {
                renderer = new CustomRenderer(arr2, mainCharacterIndex);
            } else if (displayDPS) {
                renderer = new CustomRenderer(arr1, mainCharacterIndex);
            }
        } else {
            renderer = new CustomRenderer(arr1, mainCharacterIndex);
        }

        renderer.setSeriesItemLabelFont(0, font);
        df = new DecimalFormat("##,###");
        renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", df));
        renderer.setItemLabelsVisible(true);

        plot.setRenderer(renderer);

        renderer.setDrawBarOutline(true);

        CategoryAxis domainAxis = plot.getDomainAxis();
        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        domainAxis.setTickLabelFont(font);
        //CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));

        BufferedImage image = chart.createBufferedImage(jLabel1.getSize().width, jLabel1.getSize().height);
        
        jLabel1.setIcon(new ImageIcon(image));
        if (!this.sameComputer) {
            //this.repaint();
        }
    }

    private void exportParse(int index, boolean dpsParse, boolean zonewide, boolean history) {
        //System.out.println(parses);
        StringBuffer dps;
        StringBuffer heal;

        if (!history) {
            if (!zonewide) {
                heal = parses.getHealParse(index);
                dps = parses.getDPSParse(index);
            } else {
                dps = parses.getZonewideDPSParse();
                heal = parses.getZonewideHealParse();
            }
        } else {
            heal = parses.getHistoryHealParse();
            dps = parses.getHistoryDPSParse();
        }

        //.substring(this.props.getProperty("dpsParsePrefix").length() + 1)
        String strDps = dps.toString();
        String[] split = strDps.split("\n");
        strDps = "";
        for (int x = 0; x < split.length; x++) {
            if (!split[x].equalsIgnoreCase("")) {
                //System.out.println(split[x]);
                strDps += split[x].substring(this.props.getProperty("dpsParsePrefix").length() + 1) + "\n";
            }
        }

        String strHeal = heal.toString();
        split = strHeal.split("\n");
        strHeal = "";
        for (int x = 0; x < split.length; x++) {
            if (!split[x].equalsIgnoreCase("")) {
                //System.out.println(split[x]);
                strHeal += split[x].substring(this.props.getProperty("healParsePrefix").length() + 1) + "\n";
            }
        }

        String parse = (dpsParse ? dps.toString() : heal.toString());
        if (Boolean.parseBoolean(this.props.getProperty("autoDisplayParsePreview"))) {
            if (this.parseWindow == null || !this.parseWindow.isVisible()) {
                this.parseWindow = new ParsePreviewWindow(parse);
                this.parseWindow.setBounds(this.getX(), this.getY() + (this.getHeight() - this.parseWindow.getHeight()),
                        this.parseWindow.getWidth(), this.parseWindow.getHeight());
                this.parseWindow.setDefaultCloseOperation(this.DISPOSE_ON_CLOSE);
                this.parseWindow.setVisible(true);
                this.parseWindow.setAlwaysOnTop(true);
                this.parseWindow.setTextArea(parse);
            } else {
                this.parseWindow.setTextArea(parse);
            }
        }

        StringSelection ss = new StringSelection((dpsParse ? strDps : strHeal));
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);

        File dpsOutput = new File(this.props.getProperty("doFileCommandsPath") + "dps.txt");
        File healOutput = new File(this.props.getProperty("doFileCommandsPath") + "heal.txt");
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(dpsOutput));
            bw.write(dps.toString());
            bw.close();

            bw = new BufferedWriter(new FileWriter(healOutput));
            bw.write(heal.toString());
            bw.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }

        String beep = this.props.getProperty("parseCopyBeep");
        if (beep != null) {
            if (Boolean.parseBoolean(beep)) {
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }
    private ParseContainer parses = new ParseContainer();
    private boolean connected = false;

    public void setConnected(boolean con) {
        this.connected = con;
    }

    public void sendData(Object o) {
        if (Boolean.parseBoolean(this.props.getProperty("sendData"))) {
            if (o instanceof Attack) {
                Attack a = (Attack)o;
                a.setOriginatingServer(this.machineName);
                try {
                    if (this.connected) {
                        if (this.commThread != null) {
                            this.commThread.sendData(o);
                        }
                    } else {
                        // nothing - let the encounter start handle it
                    }
                } catch (IOException ex) {
                    connected = false;
                    Logger.getLogger(LiteGui.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else if (o instanceof Line) {
                ((Line) o).setCharacter(this.getMainCharacter());
                ((Line) o).setServer(this.getServer());
                try {
                    if (this.connected) {
                        if (this.commThread != null) {
                            this.commThread.sendData(o);
                        }
                    } else {
                        // nothing - let the encounter start handle it
                    }
                } catch (IOException ex) {
                    connected = false;
                    Logger.getLogger(LiteGui.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else if (o instanceof String) {
                System.out.println(o.toString());
            }
        }
    }

    public boolean checkForServer() {
        boolean rval = false;
        if (Boolean.parseBoolean(this.props.getProperty("sendData"))) {
            if (this.getMainCharacter() != null) {
                try {
                    if (!this.connected) {
                        rval = true;
                        this.commThread = new CommSocketThread(this);
                        this.commThread.start();
                        Line connectLine = new Line("", Line.CONNECT);
                        connectLine.setCharacter(this.getMainCharacter());
                        connectLine.setServer(this.getServer());
                        this.commThread.sendData(connectLine);
                    }
                } catch (ConnectException ex) {
                    ex.printStackTrace();
                    // do nothing - server is down.
                } catch (IOException ex) {
                    Logger.getLogger(LiteGui.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return rval;
    }
    
    public void addEncounter(Encounter enc, int index) {
        //this.sendEncounter(enc);
        
        this.updateEncounterTable(enc);
        this.updateEncounterGraph(enc);

        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree.getModel();
        tmpModel.removeNodeFromParent((MutableTreeNode) tmpModel.getChild(root, 1));
        //root.getChildAt(0));

        Duration encounterDuration = enc.getEncounterDuration();
        if (encounterDuration.getDurationInSeconds() > 0) {
            if (this.propsUpdated) {
                this.loadProperties();
            }

            int longest = 0;
            for (int x = 0; x < dpsers.size(); x++) {
                String line = (String) dpsers.get(x);
                if (!line.contains("Encounter")) {
                    String name = line.substring(0, line.indexOf("  "));
                    if (x < 8) {
                        int length = name.length();
                        if (length > longest) {
                            longest = length;
                        }
                    }
                }
            }

            StringBuffer parse = new StringBuffer();
            for (int x = 0; x < dpsers.size(); x++) {
                String line = (String) dpsers.get(x);
                String name = line.substring(0, line.indexOf("  ")).trim();
                String rest = line.substring(line.indexOf("  ")).trim();

                if (!line.contains("Encounter")) {
                    while ((longest - name.length()) > 0) {
                        name += " ";
                    }
                }
                String write = this.props.getProperty("dpsParsePrefix") + " " + name + " " + rest + "\r\n";
                //bw.write(write);
                parse.append(write);

                if (x == 16) {
                    x = dpsers.size();
                }
            }
            //bw.close();
            parses.addToDPSParse(parse);

            DecimalFormat df = new DecimalFormat("###.##");

            parse = new StringBuffer();

            //bw = new BufferedWriter(new FileWriter(healOutput));
            for (int x = 0; x < healers.size(); x++) {
                String line = (String) healers.get(x);
                String name = line.substring(0, line.indexOf(" ")).trim();
                String rest = line.substring(line.indexOf(" "));
                double amount = 0;
                if (!line.contains("Encounter")) {
                    amount = Double.parseDouble(line.substring(line.indexOf("|") + 2));
                    //System.out.println(line + ", " + amount + ", " + totalHealing);
                    while ((_longest - name.length()) > 0) {
                        name += " ";
                    }
                }
                double mult = 100;
                String heal = this.props.getProperty("healParsePrefix") + " " + name + rest +
                        (!line.contains("Encounter") ? " | " + df.format(((amount / totalHealing) * mult)) + "%" : "") + "\r\n";
                //bw.write(heal);
                parse.append(heal);
                if (x == 16) {
                    x = healers.size();
                }
            }
            parses.addToHealParse(parse);

            String whichAutoParse = this.props.getProperty("whichAutoParse");
            if (whichAutoParse != null) {
                if (whichAutoParse.equalsIgnoreCase("DPS Parse")) {
                    this.exportParse(0, true, false, false);
                } else {
                    this.exportParse(0, false, false, false);
                }
            } else {
                this.exportParse(0, true, false, false);
            }
            this.encounterHistory.add(0, enc);

            DefaultMutableTreeNode combatant = null;
            
             //= enc.getMainEnemyCombatant();
            Combatant comb = enc.getCombatant(enc.getMainEnemy());
            try {
                //String className = this.getCombatantClass(comb.getName(), comb.getAttacks());
                //comb.setCareer(className);
                enc.setTitle(comb.getName() + (!comb.getCareer().equalsIgnoreCase("") ? " (" + comb.getCareer() + ")": "") + " [" + enc.getEncounterDuration().getDuration() + "]");
            } catch (NullPointerException ex) {
                //nothing
            }
            DefaultMutableTreeNode encounter = new DefaultMutableTreeNode(enc);

            ArrayList attacks = null;
            ArrayList combatants = enc.getCombatants();
            ArrayList combatantNodes = new ArrayList();

            for (int x = 0; x < combatants.size(); x++) {
                Combatant tmp = (Combatant) combatants.get(x);
                if (tmp.getAvoidedAtLeastOne() == null) {
                    tmp.setAvoidedAtLeastOne("false");
                }
                long zonewide = 0;

                String combatantName = tmp.getName();

                if (!combatantName.equalsIgnoreCase("Unknown")) {
                    if (enc.isAlly(combatantName)) {
                        if (this.zonewideDPS.containsKey(combatantName)) {
                            zonewide = (Long) this.zonewideDPS.get(combatantName);
                        }
                        zonewide += tmp.getTotalDamageDealt();
                        this.zonewideDPS.put(combatantName, zonewide);
                    }

//                    String careerName = this.getCombatantClass(combatantName, tmp.getAttacks());
//                    tmp.setCareer(careerName);
                    //tmp.setName(tmp + careerName);
                    combatantNodes.add(new CombatantNode(this.calculateEncounterData(tmp, enc.getEncounterDuration()), combatantName));
                }
            }

            Collections.sort(combatantNodes, new CombatantNode());

            for (int i = 0; i < combatantNodes.size(); i++) {
                CombatantNode cNode = (CombatantNode) combatantNodes.get(i);
                encounter.add(cNode.getNode());
            }

            if (index == -1) {
                Duration totalTime = (Duration) root.getUserObject();
                totalTime.addDuration(enc.getEncounterDuration());
                root.setUserObject(totalTime);
                
                tmpModel.insertNodeInto(encounter, root, 1);
                jTree.expandRow(0);

                //long before = System.currentTimeMillis();
                this.zonewideEncounter.addEncounter(enc, enc.getEncounterDuration()); //(Duration) root.getUserObject()
                //System.out.println("Adding encounter DATA took " + (System.currentTimeMillis() - before) + "ms");

                DefaultMutableTreeNode zonewideNode = (DefaultMutableTreeNode) tmpModel.getChild(root, 0);
                tmpModel.removeNodeFromParent(zonewideNode);
                zonewideNode = new DefaultMutableTreeNode("Zonewide");

                ArrayList zc = this.zonewideEncounter.getCombatants();
                combatantNodes = new ArrayList();
                for (int i = 0; i < zc.size(); i++) {
                    Combatant zcc = (Combatant) zc.get(i);
                    if (!zcc.getName().equalsIgnoreCase("Unknown")) {
//                        String careerName = this.getCombatantClass(zcc.getName(), zcc.getAttacks());
//                        zcc.setCareer(careerName);
                        combatantNodes.add(new CombatantNode(
                                this.calculateEncounterData(zcc, this.zonewideEncounter.getEncounterDuration()), zcc.getName()));
                    }
                }
                Collections.sort(combatantNodes, new CombatantNode());

                for (int i = 0; i < combatantNodes.size(); i++) {
                    CombatantNode cNode = (CombatantNode) combatantNodes.get(i);
                    zonewideNode.add(cNode.getNode());
                }

                zonewideNode.setUserObject(this.zonewideEncounter);
                tmpModel.insertNodeInto(zonewideNode, root, 0);

                df = new DecimalFormat("###.##");

                ArrayList zwc = this.zonewideEncounter.getCombatants();
                ArrayList zwdps = new ArrayList();
                ArrayList zwHealing = new ArrayList();
                double totalZWdps = 0;
                double totalHealingDone = 0;
                for (int x = 0; x < zwc.size(); x++) {
                    Combatant c = (Combatant) zwc.get(x);
                    if (this.zonewideEncounter.isAlly(c.getName())) {
                        double tmpDPS = c.getExtendedDPS();
                        double tmpHealing = c.getTotalHealingDone();
                        totalZWdps += tmpDPS;
                        totalHealingDone += tmpHealing;
                        zwdps.add(props.getProperty("dpsParsePrefix") + " " + c.getName() + " | " + df.format(tmpDPS));
                        zwHealing.add(props.getProperty("healParsePrefix") + " " + c.getName() + " | " + tmpHealing);
                    }
                }

                ParseContainer sorter = new ParseContainer();
                Collections.sort(zwdps, sorter);
                Collections.sort(zwHealing, sorter);

                zwdps.add(0, props.getProperty("dpsParsePrefix") + " Total Zonewide DPS: {" + df.format(totalZWdps) + "} - " + this.zonewideEncounter.getEncounterDuration().toString().substring(15));

                df = new DecimalFormat("###");
                zwHealing.add(0, props.getProperty("healParsePrefix") + " Total Zonewide Healing: {" + df.format(totalHealingDone) + "} - " + this.zonewideEncounter.getEncounterDuration().toString().substring(15));
                StringBuffer tmpBuf = new StringBuffer();

                int max = 0;
                if (zwdps.size() >= 16) {
                    max = 16;
                } else {
                    max = zwdps.size();
                }
                for (int x = 0; x < max; x++) {
                    String tmp = (String) zwdps.get(x);
                    tmpBuf.append(tmp + "\n");
                }
                this.parses.setZonewideDPSParse(tmpBuf);

                df = new DecimalFormat("###.##");
                max = 0;
                if (zwHealing.size() >= 16) {
                    max = 16;
                } else {
                    max = zwHealing.size();
                }
                tmpBuf = new StringBuffer();
                for (int x = 0; x < max; x++) {
                    String tmp = (String) zwHealing.get(x);
                    if (!tmp.contains("Total")) {
                        double num = Double.parseDouble(tmp.substring(tmp.lastIndexOf(" ") + 1).trim());
                        double percent = (num / totalHealingDone) * 100;
                        tmpBuf.append(tmp + " | " + (percent > 0 ? df.format(percent) : "0") + "%\n");
                    } else {
                        tmpBuf.append(tmp + "\n");
                    }
                }
                this.parses.setZonewideHealParse(tmpBuf);
            } else {
                tmpModel.insertNodeInto(encounter, root, index);
                jTree.expandRow(0);
            }
        }
    }

//    private String getCombatantClass(String combatantName, ArrayList attacks) {
//        String rval = "";
//        for (Object object : attacks) {
//            Attack a = (Attack) object;
//            if (!a.getAttackName().equalsIgnoreCase("attack") && !a.getAttackName().equalsIgnoreCase("axe toss")) {
//                if (a.getAttackDirectionIntRelativeToCombatant(combatantName) == Attack.ATTACK_TYPE_OUTGOING) {
//                    rval = this.combatTail.dataHandler.getCareerName(a.getAttackName());
//                    if (rval != null) {
//                        //rval = " (" + rval + ")";
//                        break;
//                    } else {
//                        rval = "";
//                    }
//                }
//            }
//        }
//        return rval;
//    }
    
    public Properties getProgramProperties() {
        return this.props;
    }

    public void addPlaceHolder(String title) {
        DefaultMutableTreeNode placeholder = new DefaultMutableTreeNode(title + " in progress...");
        DefaultTreeModel tmpModel = (DefaultTreeModel) jTree.getModel();
        tmpModel.insertNodeInto(placeholder, root, 1);
        jTree.expandRow(0);
        //root.insert(placeholder, 0);
        //this.updateTree(jTree);
    }

    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
        jLabel1.setSize(layeredPane.getWidth(), layeredPane.getHeight());
        if (!this.sameComputer) {
            //this.repaint();
        }
    }//GEN-LAST:event_formWindowOpened

    private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
        if (this.parseWindow != null && this.parseWindow.isVisible()) {
            this.parseWindow.dispose();
        }

        if (this.timer != null && this.timer.isVisible()) {
            this.timer.dispose();
        }
        
        if (this.combatTail != null) {
            this.combatTail.stopRunning();
        }
//        if (this.systemTail != null) {
//            this.systemTail.stopRunning();
//        }
        
        this.props.setProperty("guiX", this.getX() + "");
        this.props.setProperty("guiY", this.getY() + "");
        this.props.setProperty("guiWidth", this.getWidth() + "");
        this.props.setProperty("guiHeight", this.getHeight() + "");
        
        if (this.commThread != null && Boolean.parseBoolean(this.props.getProperty("sendData"))) {
            //this.sendData("::removeid::" + this.characterID);
            Line line = new Line("", Line.DISCONNECT);
            line.setCharacter(this.getMainCharacter());
            line.setServer(this.getServer());
            this.sendData(new Line("", Line.DISCONNECT));
            this.commThread.closeSocket();
        }
        //this.storeRespawnTimers();
        
        this.storeEncounterHistory();
        if (this.restart) {
//            System.out.println("restarting...");
            try {
                String[] cmd = new String[3];
                cmd[0] = "start javaw";
                cmd[1] = "-jar";
                String currentFile = null;
                switch (Integer.parseInt(this.props.getProperty("currentFile"))) {
                    case 0:
                        currentFile = "LCT1.jar";
                        this.props.setProperty("currentFile", "1");
                        saveProperties();
                        break;
                    case 1:
                        currentFile = "LCT.jar";
                        this.props.setProperty("currentFile", "1");
                        saveProperties();
                        break;
                    default:
                        break;
                }
                cmd[2] = currentFile;
                Process process = Runtime.getRuntime().exec("start1.bat");
                System.exit(0);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } else {
            switch (Integer.parseInt(this.props.getProperty("currentFile"))) {
                case 1:
                    try {
                        copy(new File("LCT1.jar"), new File("LCT.jar"));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    break;
                default:
                    break;
            }
        }
    }//GEN-LAST:event_formWindowClosed

    public void startParse() {
        this.jLabel2.setText("Parsing started.");
        this.group.setSelected(toggleStart.getModel(), true);
        this.group.setSelected(toggleStop.getModel(), false);
        this.group.setSelected(togglePause.getModel(), false);
    }

    public void stopParse() {
        this.jLabel2.setText("Parsing stopped. Press play to restart.");
        this.group.setSelected(toggleStart.getModel(), false);
        this.group.setSelected(toggleStop.getModel(), true);
        this.group.setSelected(togglePause.getModel(), false);
        combatTail = null;
//        systemTail = null;
    }

    private void togglePauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_togglePauseActionPerformed
        if (this.combatTail != null) {
            this.combatTail.pause();
            this.jLabel2.setText("Parsing paused... Press play to resume.");
        } else {
            this.group.setSelected(this.toggleStop.getModel(), true);
        }
}//GEN-LAST:event_togglePauseActionPerformed

    private void toggleStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggleStopActionPerformed
        if (this.combatTail != null) {
            this.jLabel2.setText("Parsing stopped. Press play to restart.");
            this.combatTail.stopRunning();
//            this.systemTail.stopRunning();
//            systemTail = null;
            combatTail = null;
        }
}//GEN-LAST:event_toggleStopActionPerformed

    private void toggleStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggleStartActionPerformed
        if (this.combatTail != null) {
//            this.systemTail.startParsing();
            this.combatTail.startParsing();
        } else {
            this.combatTail = new Tail(this, Tail.COMBAT_LOG);
            combatTail.start();
//            this.systemTail = new Tail(this, Tail.SYSTEM_LOG);
//            systemTail.start();
        }
        this.jLabel2.setText("Parsing started.");
}//GEN-LAST:event_toggleStartActionPerformed

    private void jMenuItem16ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem16ActionPerformed
        if (this.treeRows != null) {
            TreePath[] paths = (TreePath[]) this.treeRows;
            Encounter tmp = null;
            int index = 0;
            for (int x = 0; x < paths.length; x++) {
                TreePath treePath = paths[x];
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent();
                Object nodeData = node.getUserObject();
                if (nodeData instanceof Encounter) {
                    Encounter enc = (Encounter) nodeData;
                    DefaultTreeModel model = (DefaultTreeModel) jTree.getModel();

                    if (!enc.isZonewide()) {
                        if (tmp == null) {
                            tmp = enc;
                        } else {
                            tmp.addEncounter(enc, enc.getEncounterDuration());
                        }

                        if (x == paths.length - 1) {
                            index = model.getIndexOfChild(root, node);
                            //DefaultMutableTreeNode newNode = new DefaultMutableTreeNode();
                            //newNode.setUserObject(tmp);
                        } else {
                            model.removeNodeFromParent(node);
                        }
                    }
                }
            }
            this.addEncounter(tmp, index);
            this.treeRows = null;
        }
    }//GEN-LAST:event_jMenuItem16ActionPerformed
    
private void jMenuItem17ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem17ActionPerformed
    JoinGroup joinGroup = new JoinGroup(this);
    joinGroup.setBounds(this.getX() + (this.getWidth() / 2) - (joinGroup.getWidth() / 2),
            this.getY() + (this.getHeight() / 2) - (joinGroup.getHeight() / 2),
            joinGroup.getWidth(), joinGroup.getHeight());
    joinGroup.setVisible(true);
}//GEN-LAST:event_jMenuItem17ActionPerformed

private void jMenuItem18ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem18ActionPerformed
    if (this.inGroup) {
        root2 = new DefaultMutableTreeNode("Not In Group");
        jTree1.setModel(new DefaultTreeModel(root2));
        //this.sendData("::leavegroup::" + this.characterID);
        this.sendData(new Line("", Line.PARTY_LEAVE));
        JOptionPane.showMessageDialog(this, "You have left the group.", "Left Group", JOptionPane.INFORMATION_MESSAGE);
        this.setInGroup(false);
    }
}//GEN-LAST:event_jMenuItem18ActionPerformed

private void jMenuItem19ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem19ActionPerformed
    //this.sendData("::joingroup::" + this.characterID + ";;" + this.getMainCharacter().toLowerCase());
    Line line = new Line("", Line.PARTY_CREATE);
    line.setGroupID(this.getServer() + File.separator + this.getMainCharacter());
    line.setCharacter(this.getMainCharacter());
    line.setServer(this.getServer());
    this.sendData(line);
    //JOptionPane.showMessageDialog(this, "You have created a group.", "Created Group", JOptionPane.INFORMATION_MESSAGE);
    this.setInGroup(true);
}//GEN-LAST:event_jMenuItem19ActionPerformed

private void jMenuItem8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem8ActionPerformed
    this.storeEncounterHistory();
    this.clearEncounters();
}//GEN-LAST:event_jMenuItem8ActionPerformed

private void jMenuItem20ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem20ActionPerformed
    if (popupClicked instanceof Encounter && rowClicked > 1) {
        this.generateAvoidanceReport((Encounter)popupClicked);
    }
}//GEN-LAST:event_jMenuItem20ActionPerformed

private void jMenuItem21ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem21ActionPerformed
    this.generateAvoidanceReport(this.lastHistoryClicked);
}//GEN-LAST:event_jMenuItem21ActionPerformed

private void jMenuItem22ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem22ActionPerformed
    this.generateAvoidanceReport(this.lastHistoryClicked);
}//GEN-LAST:event_jMenuItem22ActionPerformed

private void jTreeMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeMousePressed
    if (evt.isPopupTrigger()) {
        TreePath path = jTree.getPathForLocation(evt.getX(), evt.getY());
        boolean multi = false;
        TreePath[] paths = jTree.getSelectionPaths();
        if (paths != null && paths.length > 1) {
            multi = true;
        }

        if (!multi) {
            jTree.setSelectionPath(path);

            DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
            rowClicked = jTree.getRowForLocation(evt.getX(), evt.getY());
            //(DefaultMutableTreeNode)root.getChildAt(jTree.getClosestRowForLocation(evt.getX(), evt.getY()));

            if (node == null) {
                return;
            }

            Object nodeData = node.getUserObject();

            if (nodeData instanceof Encounter) {
                popupClicked = (Encounter) nodeData;
                String parseCustom = this.props.getProperty("parseCustom");
                if (parseCustom == null) {
                    parseCustom = "false";
                }
                if (((Encounter) popupClicked).isZonewide() && Boolean.parseBoolean(parseCustom)) {
                    jPopupMenu7.show(jTree, evt.getX(), evt.getY());
                } else {
                    jPopupMenu2.show(jTree, evt.getX(), evt.getY());
                }
            } else if (nodeData instanceof Combatant) {
                popupClicked = (Combatant) nodeData;
                jPopupMenu1.show(jTree, evt.getX(), evt.getY());
            } else if (nodeData instanceof AttackHashMap) {
                lastAttackClicked = ((AttackHashMap) nodeData).toString();
                if (this.arrAlways.contains(lastAttackClicked)) {
                    this.jCheckBoxMenuItem2.setSelected(true);
                    this.jCheckBoxMenuItem3.setSelected(false);
                } else {
                    this.jCheckBoxMenuItem2.setSelected(false);
                }
                if (this.arrNever.contains(lastAttackClicked)) {
                    this.jCheckBoxMenuItem3.setSelected(true);
                    this.jCheckBoxMenuItem2.setSelected(false);
                } else {
                    this.jCheckBoxMenuItem3.setSelected(false);
                }
                jPopupMenu5.show(jTree, evt.getX(), evt.getY());
            } else if (nodeData instanceof Duration) {
                jPopupMenu11.show(jTree, evt.getX(), evt.getY());
            }
        } else {
            //jTree.setSelectionPaths(paths);
            //DefaultTreeModel model = (DefaultTreeModel) jTree.getModel();
            //boolean
            treeRows = paths;
            this.jPopupMenu9.show(jTree, evt.getX(), evt.getY());
        }
    }
}//GEN-LAST:event_jTreeMousePressed

private void jTree1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTree1MousePressed
        jTree1.setSelectionPath(jTree1.getPathForLocation(evt.getX(), evt.getY()));
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();

        if (node == null) {
            return;
        }

        if (evt.isPopupTrigger()) {
            Object nodeData = node.getUserObject();

            if (nodeData instanceof RespawnTimer) {
                RespawnTimer timer = (RespawnTimer) nodeData;
                jCheckBoxMenuItem1.setSelected(!timer.isThrowaway());
                jPopupMenu4.show(jTree1, evt.getX(), evt.getY());
            } else {
                jPopupMenu10.show(jTree1, evt.getX(), evt.getY());
            }
        }
}//GEN-LAST:event_jTree1MousePressed

private void historyTreeMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_historyTreeMousePressed
    historyTree.setSelectionPath(historyTree.getPathForLocation(evt.getX(), evt.getY()));
    DefaultMutableTreeNode node = (DefaultMutableTreeNode) historyTree.getLastSelectedPathComponent();
    TreePath pathClicked = historyTree.getSelectionPath();
    DefaultTreeModel tmpModel = (DefaultTreeModel) historyTree.getModel();

    if (node != null) {
        if (evt.isPopupTrigger()) {
            Object nodeData = node.getUserObject();
            if (nodeData instanceof Encounter) {
                lastHistoryClicked = (Encounter) nodeData;
                String parseCustom = this.props.getProperty("parseCustom");
                if (parseCustom == null) {
                    parseCustom = "false";
                }
                if (((Encounter) lastHistoryClicked).isZonewide() && Boolean.parseBoolean(parseCustom)) {
                    jPopupMenu8.show(historyTree, evt.getX(), evt.getY());
                } else {
                    jPopupMenu6.show(historyTree, evt.getX(), evt.getY());
                }
            } else {
                jPopupMenu3.show(historyTree, evt.getX(), evt.getY());
            }
        }
    }
}//GEN-LAST:event_historyTreeMousePressed

    public void generateAvoidanceReport(Encounter enc) {
        AvoidanceReportWindow avoidReport = new AvoidanceReportWindow(enc);
        avoidReport.setBounds(this.getX() + (this.getWidth() / 2) - (avoidReport.getWidth() / 2),
                this.getY() + (this.getHeight() / 2) - (avoidReport.getHeight() / 2),
                avoidReport.getWidth(), avoidReport.getHeight());
                avoidReport.setVisible(true);
    }

    private boolean inGroup = false;
    public boolean inGroup() {
        return this.inGroup;
    }
    
    public void setInGroup(boolean inGroup) {
        this.inGroup = inGroup;
    }
    
    public void removeFromGroup(String name) {
        DefaultTreeModel model2 = (DefaultTreeModel)jTree1.getModel();
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)model2.getChild(root2, model2.getIndexOfChild(root2, name));
        node.removeFromParent();
    }
    
    public void addToGroup(String name) {
        DefaultTreeModel model2 = (DefaultTreeModel)jTree1.getModel();
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
        model2.insertNodeInto(node, root2, 1);
        jTree1.expandRow(0);
    }
    
    public void groupAlreadyExists(String id) {
        JOptionPane.showMessageDialog(this, "The group: '" + id + "' already exists.", "Group Already Exists", JOptionPane.ERROR_MESSAGE);
    }
    
    public void groupDoesNotExist(String id) {
        JOptionPane.showMessageDialog(this, "The group: '" + id + "' was not found.", "Group Not Found", JOptionPane.ERROR_MESSAGE);
    }
    
    public void createGroup(String id) {
        this.setInGroup(true);
        root2 = new DefaultMutableTreeNode(id);
        jTree1.setModel(new DefaultTreeModel(root2));
        JOptionPane.showMessageDialog(this, "You have created the group: '" + id + "'", "Created Group", JOptionPane.INFORMATION_MESSAGE);
    }
    
    public void joinGroup(String groupName) {
        this.setInGroup(true);
        root2 = new DefaultMutableTreeNode(groupName);
        jTree1.setModel(new DefaultTreeModel(root2));
        JOptionPane.showMessageDialog(this, "You have successfully joined the group: '" + groupName + "'", "Joined Group", JOptionPane.INFORMATION_MESSAGE);
    }

    public void reloadGroupMembers(ArrayList members, String id) {
        DefaultTreeModel model2 = (DefaultTreeModel)jTree1.getModel();
        root2 = new DefaultMutableTreeNode(id);
        jTree1.setModel(new DefaultTreeModel(root2));
        for (Object object : members) {
            String charName = (String)object;
            if (!charName.contains(this.getMainCharacter().toLowerCase())) {
                charName = charName.substring(charName.indexOf(File.separator) + 1);
                String firstLetter = charName.substring(0, 1).toUpperCase();
                charName = firstLetter + charName.substring(1);
                model2.insertNodeInto(new DefaultMutableTreeNode(charName), root2, 0);
            }
        }
        jTree1.expandRow(0);
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try {
            //Toolkit.getDefaultToolkit().getSystemEventQueue().push(new TracingEventQueue());
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }

        long before = System.currentTimeMillis();
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new LiteGui().setVisible(true);
            }
        });

        //System.out.println("Checking for new Respawn Timers...");
        //LCTClient client = new LCTClient();
        //try {
//            HashMap test = client.getTimers();
//            Iterator iter = test.keySet().iterator();
//            while (iter.hasNext()) {
//                //RespawnTimer tmp = (RespawnTimer)test.get(iter.next());
//                HashMap check = (HashMap)test.get(iter.next());
//                System.out.println(check.size());
//                Iterator iter2 = check.keySet().iterator();
//                while (iter2.hasNext()) {
//                    System.out.println(check.get(iter2.next()).getClass().getName());
//                }
//                //System.out.println("Official respawn: " + tmp.getCombatantName() + 
//                //        ", duration: " + tmp.getTotalDuration().getDuration());
//            }

        //System.out.println("This version = " + version + ", latest version = " + getVersionFromURL());
        //} catch (NullPointerException ex) {
        //    throwError(2);
        //ex.printStackTrace();
        //}
        System.out.println("Program initialization took " + (System.currentTimeMillis() - before) + "ms.");
    }

    public static String getVersionChanges() {
        String rval = null;
        BufferedReader br = null;
        StringBuffer buf = new StringBuffer();
        try {
            URL url = new URL("http://lcteq2.appspot.com/lctmetadata?r=changes");
            br = new BufferedReader(new InputStreamReader(url.openStream()));

            String line;
            while ((line = br.readLine()) != null) {
                buf.append(line + "\n");
            }
            rval = buf.toString();
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                br.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return rval.trim();
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getVersionFromURL() {
        String rval = null;
        BufferedReader br = null;
        try {
            URL url = new URL("http://lcteq2.appspot.com/lctmetadata?r=version");
            br = new BufferedReader(new InputStreamReader(url.openStream()));

            String line;
            while ((line = br.readLine()) != null) {
                rval = line;
            }
        } catch (MalformedURLException ex) {
            //ex.printStackTrace();
        } catch (IOException ex) {
            this.jLabel2.setText("Could not connect to upgrade server.");
//            this.props.setProperty("autoVersionCheck", "false");
            this.saveProperties();
//            this.throwError(2);
        //ex.printStackTrace();
        } finally {
            try {
                br.close();
            } catch (IOException ex) {
                //ex.printStackTrace();
            }
        }
        return rval;
    }

    public void updateTree(JTree tree) {
        DefaultTreeModel tmpModel = (DefaultTreeModel) tree.getModel();
        if (tmpModel.getChildCount(root2) > 0) {
            for (int x = 0; x < tmpModel.getChildCount(root2); x++) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tmpModel.getChild(root2, x);
                tmpModel.nodeChanged(node);
            }
        //tmpModel.reload();
        //tree.expandRow(0);
        }
    }
    private ArrayList healers = new ArrayList();
    private ArrayList dpsers = new ArrayList();
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTree historyTree;
    private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItem1;
    private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItem2;
    private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItem3;
    private javax.swing.JLabel jLabel1;
    public javax.swing.JLabel jLabel2;
    private javax.swing.JMenu jMenu;
    private javax.swing.JMenuBar jMenuBar;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem10;
    private javax.swing.JMenuItem jMenuItem11;
    private javax.swing.JMenuItem jMenuItem12;
    private javax.swing.JMenuItem jMenuItem13;
    private javax.swing.JMenuItem jMenuItem14;
    private javax.swing.JMenuItem jMenuItem15;
    private javax.swing.JMenuItem jMenuItem16;
    private javax.swing.JMenuItem jMenuItem17;
    private javax.swing.JMenuItem jMenuItem18;
    private javax.swing.JMenuItem jMenuItem19;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JMenuItem jMenuItem20;
    private javax.swing.JMenuItem jMenuItem21;
    private javax.swing.JMenuItem jMenuItem22;
    private javax.swing.JMenuItem jMenuItem3;
    private javax.swing.JMenuItem jMenuItem4;
    private javax.swing.JMenuItem jMenuItem5;
    private javax.swing.JMenuItem jMenuItem6;
    private javax.swing.JMenuItem jMenuItem7;
    private javax.swing.JMenuItem jMenuItem8;
    private javax.swing.JMenuItem jMenuItem9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPopupMenu jPopupMenu1;
    private javax.swing.JPopupMenu jPopupMenu10;
    private javax.swing.JPopupMenu jPopupMenu11;
    private javax.swing.JPopupMenu jPopupMenu2;
    private javax.swing.JPopupMenu jPopupMenu3;
    private javax.swing.JPopupMenu jPopupMenu4;
    private javax.swing.JPopupMenu jPopupMenu5;
    private javax.swing.JPopupMenu jPopupMenu6;
    private javax.swing.JPopupMenu jPopupMenu7;
    private javax.swing.JPopupMenu jPopupMenu8;
    private javax.swing.JPopupMenu jPopupMenu9;
    private javax.swing.JScrollPane jScrollPane;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane5;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTree jTree;
    public javax.swing.JTree jTree1;
    private javax.swing.JLayeredPane layeredPane;
    private javax.swing.JToggleButton togglePause;
    private javax.swing.JToggleButton toggleStart;
    private javax.swing.JToggleButton toggleStop;
    // End of variables declaration//GEN-END:variables
}